diff options
author | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-01-11 14:48:57 +0900 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-01-17 14:05:16 +0900 |
commit | 4f5e64fdea88ba7362d77a6d42ea22cf13d3323f (patch) | |
tree | 42d0e98027484e564e56a10cb748154cec554742 /src | |
parent | b1105da1dae316081f34c71df0d5fdd4afabb9f8 (diff) |
eina_freeq: Add mode for postponed deletion
While this reuses the existing (but new) infrastructure of
eina_freeq, the mode of operation and objective is very different
from the default freeq.
By default, any object added to the freeq is basically already
freed from the user point of view, and the freeq itself only adds
a tiny layer of memory safety by deferring the actual call to free
and optionally filling the memory blob with a pattern ('wwwww...').
This is mostly thread-safe (requires thread-safe free functions).
This new type I called postponed is intended to store objects that
will be short lived. This is not thread safe as the life of the
objects added to this queue depends on the thread that adds to
the queue. The main intent is to introduce a new API for short-lived
strings.
@feature
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/eina/eina_freeq.c | 133 | ||||
-rw-r--r-- | src/lib/eina/eina_freeq.h | 70 | ||||
-rw-r--r-- | src/lib/eina/eina_main.c | 2 | ||||
-rw-r--r-- | src/tests/eina/eina_test_freeq.c | 84 |
4 files changed, 244 insertions, 45 deletions
diff --git a/src/lib/eina/eina_freeq.c b/src/lib/eina/eina_freeq.c index 17459dc5ee..0485501c03 100644 --- a/src/lib/eina/eina_freeq.c +++ b/src/lib/eina/eina_freeq.c | |||
@@ -45,14 +45,16 @@ struct _Eina_FreeQ_Block | |||
45 | 45 | ||
46 | struct _Eina_FreeQ | 46 | struct _Eina_FreeQ |
47 | { | 47 | { |
48 | Eina_Lock lock; | 48 | Eina_Lock lock; // recursive lock, unused for postponed queues (thread-local) |
49 | int count; // number of item slots used | 49 | int count; // number of item slots used |
50 | int count_max; // the maximum number of slots allowed to be used | 50 | int count_max; // maximum number of slots allowed to be used or -1 |
51 | size_t mem_max; // the maximum amount of memory allowed to be used | 51 | size_t mem_max; // the maximum amount of memory allowed to be used |
52 | size_t mem_total; // current total memory known about in the queue | 52 | size_t mem_total; // current total memory known about in the queue |
53 | Eina_FreeQ_Block *blocks; // the list of blocks of free items | 53 | Eina_FreeQ_Block *blocks; // the list of blocks of free items |
54 | Eina_FreeQ_Block *block_last; // the last block to append items to | 54 | Eina_FreeQ_Block *block_last; // the last block to append items to |
55 | int bypass; // 0 if not to bypass, 1 if we should bypass | 55 | Eina_Bool bypass; // 0 if not to bypass, 1 if we should bypass |
56 | Eina_Bool postponed; // 1 if postponed type of freeq (eg. temp strings) | ||
57 | Eina_Bool unlocked; // 0 by default, 1 if thread-local (lock not used) | ||
56 | }; | 58 | }; |
57 | 59 | ||
58 | // ========================================================================= // | 60 | // ========================================================================= // |
@@ -67,6 +69,13 @@ static size_t _eina_freeq_mem_max = ITEM_MEM_MAX; | |||
67 | 69 | ||
68 | // ========================================================================= // | 70 | // ========================================================================= // |
69 | 71 | ||
72 | #define LOCK_FQ(fq); do { \ | ||
73 | if (!fq->unlocked) eina_lock_take(&(fq->lock)); } while(0) | ||
74 | #define UNLOCK_FQ(fq); do { \ | ||
75 | if (!fq->unlocked) eina_lock_release(&(fq->lock)); } while(0) | ||
76 | |||
77 | // ========================================================================= // | ||
78 | |||
70 | static inline void | 79 | static inline void |
71 | _eina_freeq_fill_do(void *ptr, size_t size) | 80 | _eina_freeq_fill_do(void *ptr, size_t size) |
72 | { | 81 | { |
@@ -146,18 +155,20 @@ _eina_freeq_process(Eina_FreeQ *fq) | |||
146 | static void | 155 | static void |
147 | _eina_freeq_flush_nolock(Eina_FreeQ *fq) | 156 | _eina_freeq_flush_nolock(Eina_FreeQ *fq) |
148 | { | 157 | { |
158 | if (fq->postponed) return; | ||
159 | |||
149 | while ((fq->count > fq->count_max) || (fq->mem_total > fq->mem_max)) | 160 | while ((fq->count > fq->count_max) || (fq->mem_total > fq->mem_max)) |
150 | _eina_freeq_process(fq); | 161 | _eina_freeq_process(fq); |
151 | } | 162 | } |
152 | 163 | ||
153 | // ========================================================================= // | 164 | // ========================================================================= // |
154 | 165 | ||
155 | EAPI Eina_FreeQ * | 166 | static Eina_FreeQ * |
156 | eina_freeq_new(void) | 167 | _eina_freeq_new_default(void) |
157 | { | 168 | { |
158 | Eina_FreeQ *fq; | 169 | Eina_FreeQ *fq; |
159 | 170 | ||
160 | if (_eina_freeq_bypass == -1) | 171 | if (EINA_UNLIKELY(_eina_freeq_bypass == -1)) |
161 | { | 172 | { |
162 | const char *s; | 173 | const char *s; |
163 | int v; | 174 | int v; |
@@ -197,16 +208,53 @@ eina_freeq_new(void) | |||
197 | return fq; | 208 | return fq; |
198 | } | 209 | } |
199 | 210 | ||
211 | static Eina_FreeQ * | ||
212 | _eina_freeq_new_postponed(void) | ||
213 | { | ||
214 | Eina_FreeQ *fq; | ||
215 | |||
216 | fq= calloc(1, sizeof(*fq)); | ||
217 | if (!fq) return NULL; | ||
218 | fq->mem_max = 0; | ||
219 | fq->count_max = -1; | ||
220 | fq->postponed = EINA_TRUE; | ||
221 | fq->unlocked = EINA_TRUE; | ||
222 | return fq; | ||
223 | } | ||
224 | |||
225 | EAPI Eina_FreeQ * | ||
226 | eina_freeq_new(Eina_FreeQ_Type type) | ||
227 | { | ||
228 | switch (type) | ||
229 | { | ||
230 | case EINA_FREEQ_DEFAULT: | ||
231 | return _eina_freeq_new_default(); | ||
232 | case EINA_FREEQ_POSTPONED: | ||
233 | return _eina_freeq_new_postponed(); | ||
234 | default: | ||
235 | return NULL; | ||
236 | } | ||
237 | } | ||
238 | |||
200 | EAPI void | 239 | EAPI void |
201 | eina_freeq_free(Eina_FreeQ *fq) | 240 | eina_freeq_free(Eina_FreeQ *fq) |
202 | { | 241 | { |
203 | if (!fq) return; | 242 | if (!fq) return; |
204 | if (fq == _eina_freeq_main) _eina_freeq_main = NULL; | 243 | if (fq == _eina_freeq_main) _eina_freeq_main = NULL; |
205 | eina_freeq_clear(fq); | 244 | eina_freeq_clear(fq); |
206 | eina_lock_free(&(fq->lock)); | 245 | if (!fq->unlocked) eina_lock_free(&(fq->lock)); |
207 | free(fq); | 246 | free(fq); |
208 | } | 247 | } |
209 | 248 | ||
249 | EAPI Eina_FreeQ_Type | ||
250 | eina_freeq_type_get(Eina_FreeQ *fq) | ||
251 | { | ||
252 | if (fq && fq->postponed) | ||
253 | return EINA_FREEQ_POSTPONED; | ||
254 | return EINA_FREEQ_DEFAULT; | ||
255 | } | ||
256 | |||
257 | /* FIXME This function should not exist as an EAPI */ | ||
210 | EAPI void | 258 | EAPI void |
211 | eina_freeq_main_set(Eina_FreeQ *fq) | 259 | eina_freeq_main_set(Eina_FreeQ *fq) |
212 | { | 260 | { |
@@ -224,12 +272,13 @@ EAPI void | |||
224 | eina_freeq_count_max_set(Eina_FreeQ *fq, int count) | 272 | eina_freeq_count_max_set(Eina_FreeQ *fq, int count) |
225 | { | 273 | { |
226 | if (!fq) return; | 274 | if (!fq) return; |
227 | if (count < 0) count = 0; | 275 | if (fq->postponed) return; |
228 | eina_lock_take(&(fq->lock)); | 276 | if (count < 0) count = -1; |
277 | LOCK_FQ(fq); | ||
229 | fq->bypass = 0; | 278 | fq->bypass = 0; |
230 | fq->count_max = count; | 279 | fq->count_max = count; |
231 | _eina_freeq_flush_nolock(fq); | 280 | _eina_freeq_flush_nolock(fq); |
232 | eina_lock_release(&(fq->lock)); | 281 | UNLOCK_FQ(fq); |
233 | } | 282 | } |
234 | 283 | ||
235 | EAPI int | 284 | EAPI int |
@@ -238,10 +287,10 @@ eina_freeq_count_max_get(Eina_FreeQ *fq) | |||
238 | int count; | 287 | int count; |
239 | 288 | ||
240 | if (!fq) return 0; | 289 | if (!fq) return 0; |
241 | eina_lock_take(&(fq->lock)); | 290 | LOCK_FQ(fq); |
242 | if (fq->bypass) count = 0; | 291 | if (fq->bypass) count = 0; |
243 | else count = fq->count_max; | 292 | else count = fq->count_max; |
244 | eina_lock_release(&(fq->lock)); | 293 | UNLOCK_FQ(fq); |
245 | return count; | 294 | return count; |
246 | } | 295 | } |
247 | 296 | ||
@@ -249,11 +298,12 @@ EAPI void | |||
249 | eina_freeq_mem_max_set(Eina_FreeQ *fq, size_t mem) | 298 | eina_freeq_mem_max_set(Eina_FreeQ *fq, size_t mem) |
250 | { | 299 | { |
251 | if (!fq) return; | 300 | if (!fq) return; |
252 | eina_lock_take(&(fq->lock)); | 301 | if (fq->postponed) return; |
302 | LOCK_FQ(fq); | ||
253 | fq->bypass = 0; | 303 | fq->bypass = 0; |
254 | fq->mem_max = mem; | 304 | fq->mem_max = mem; |
255 | _eina_freeq_flush_nolock(fq); | 305 | _eina_freeq_flush_nolock(fq); |
256 | eina_lock_release(&(fq->lock)); | 306 | UNLOCK_FQ(fq); |
257 | } | 307 | } |
258 | 308 | ||
259 | EAPI size_t | 309 | EAPI size_t |
@@ -262,10 +312,10 @@ eina_freeq_mem_max_get(Eina_FreeQ *fq) | |||
262 | size_t mem; | 312 | size_t mem; |
263 | 313 | ||
264 | if (!fq) return 0; | 314 | if (!fq) return 0; |
265 | eina_lock_take(&(fq->lock)); | 315 | LOCK_FQ(fq); |
266 | if (fq->bypass) mem = 0; | 316 | if (fq->bypass) mem = 0; |
267 | else mem = fq->mem_max; | 317 | else mem = fq->mem_max; |
268 | eina_lock_release(&(fq->lock)); | 318 | UNLOCK_FQ(fq); |
269 | return mem; | 319 | return mem; |
270 | } | 320 | } |
271 | 321 | ||
@@ -273,22 +323,22 @@ EAPI void | |||
273 | eina_freeq_clear(Eina_FreeQ *fq) | 323 | eina_freeq_clear(Eina_FreeQ *fq) |
274 | { | 324 | { |
275 | if (!fq) return; | 325 | if (!fq) return; |
276 | eina_lock_take(&(fq->lock)); | 326 | LOCK_FQ(fq); |
277 | while (fq->count > 0) _eina_freeq_process(fq); | 327 | while (fq->count > 0) _eina_freeq_process(fq); |
278 | eina_lock_release(&(fq->lock)); | 328 | UNLOCK_FQ(fq); |
279 | } | 329 | } |
280 | 330 | ||
281 | EAPI void | 331 | EAPI void |
282 | eina_freeq_reduce(Eina_FreeQ *fq, int count) | 332 | eina_freeq_reduce(Eina_FreeQ *fq, int count) |
283 | { | 333 | { |
284 | if (!fq) return; | 334 | if (!fq) return; |
285 | eina_lock_take(&(fq->lock)); | 335 | LOCK_FQ(fq); |
286 | while ((fq->count > 0) && (count > 0)) | 336 | while ((fq->count > 0) && (count > 0)) |
287 | { | 337 | { |
288 | _eina_freeq_process(fq); | 338 | _eina_freeq_process(fq); |
289 | count--; | 339 | count--; |
290 | } | 340 | } |
291 | eina_lock_release(&(fq->lock)); | 341 | UNLOCK_FQ(fq); |
292 | } | 342 | } |
293 | 343 | ||
294 | EAPI Eina_Bool | 344 | EAPI Eina_Bool |
@@ -297,10 +347,10 @@ eina_freeq_ptr_pending(Eina_FreeQ *fq) | |||
297 | Eina_Bool pending; | 347 | Eina_Bool pending; |
298 | 348 | ||
299 | if (!fq) return EINA_FALSE; | 349 | if (!fq) return EINA_FALSE; |
300 | eina_lock_take(&(fq->lock)); | 350 | LOCK_FQ(fq); |
301 | if (fq->blocks) pending = EINA_TRUE; | 351 | if (fq->blocks) pending = EINA_TRUE; |
302 | else pending = EINA_FALSE; | 352 | else pending = EINA_FALSE; |
303 | eina_lock_release(&(fq->lock)); | 353 | UNLOCK_FQ(fq); |
304 | return pending; | 354 | return pending; |
305 | } | 355 | } |
306 | 356 | ||
@@ -314,13 +364,30 @@ eina_freeq_ptr_add(Eina_FreeQ *fq, | |||
314 | 364 | ||
315 | if (!ptr) return; | 365 | if (!ptr) return; |
316 | if (!free_func) free_func = free; | 366 | if (!free_func) free_func = free; |
317 | if ((size < _eina_freeq_fillpat_max) && (size > 0)) | 367 | if (!fq->postponed && (size < _eina_freeq_fillpat_max) && (size > 0)) |
318 | _eina_freeq_fill_do(ptr, size); | 368 | _eina_freeq_fill_do(ptr, size); |
319 | if ((!fq) || (fq->bypass)) goto insta_free; | 369 | |
320 | eina_lock_take(&(fq->lock)); | 370 | if (!fq || fq->bypass) |
371 | { | ||
372 | _eina_freeq_free_do(ptr, free_func, size); | ||
373 | return; | ||
374 | } | ||
375 | |||
376 | LOCK_FQ(fq); | ||
321 | if ((!fq->block_last) || (fq->block_last->end == ITEM_BLOCK_COUNT)) | 377 | if ((!fq->block_last) || (fq->block_last->end == ITEM_BLOCK_COUNT)) |
322 | goto newblock; | 378 | { |
323 | newblock_done: | 379 | if (!_eina_freeq_block_append(fq)) |
380 | { | ||
381 | UNLOCK_FQ(fq); | ||
382 | if (!fq->postponed) | ||
383 | _eina_freeq_free_do(ptr, free_func, size); | ||
384 | else | ||
385 | EINA_LOG_ERR("Could not add a pointer to the free queue! This " | ||
386 | "program will leak resources!"); | ||
387 | return; | ||
388 | } | ||
389 | } | ||
390 | |||
324 | fb = fq->block_last; | 391 | fb = fq->block_last; |
325 | fb->items[fb->end].ptr = ptr; | 392 | fb->items[fb->end].ptr = ptr; |
326 | fb->items[fb->end].free_func = free_func; | 393 | fb->items[fb->end].free_func = free_func; |
@@ -329,15 +396,5 @@ newblock_done: | |||
329 | fq->count++; | 396 | fq->count++; |
330 | fq->mem_total += size; | 397 | fq->mem_total += size; |
331 | _eina_freeq_flush_nolock(fq); | 398 | _eina_freeq_flush_nolock(fq); |
332 | eina_lock_release(&(fq->lock)); | 399 | UNLOCK_FQ(fq); |
333 | return; | ||
334 | newblock: | ||
335 | if (!_eina_freeq_block_append(fq)) | ||
336 | { | ||
337 | eina_lock_release(&(fq->lock)); | ||
338 | insta_free: | ||
339 | _eina_freeq_free_do(ptr, free_func, size); | ||
340 | return; | ||
341 | } | ||
342 | goto newblock_done; | ||
343 | } | 400 | } |
diff --git a/src/lib/eina/eina_freeq.h b/src/lib/eina/eina_freeq.h index eacd3a0ca9..643aa1e5ce 100644 --- a/src/lib/eina/eina_freeq.h +++ b/src/lib/eina/eina_freeq.h | |||
@@ -15,7 +15,8 @@ | |||
15 | * data at some time in the future. The main free queue will be driven | 15 | * data at some time in the future. The main free queue will be driven |
16 | * by the EFL main loop and ensure data is eventually freed. | 16 | * by the EFL main loop and ensure data is eventually freed. |
17 | * | 17 | * |
18 | * For debugging and tuning you may set the following envrionment variables: | 18 | * For debugging and tuning you may set the following environment variables, |
19 | * applicable only to free queues of the default type: | ||
19 | * | 20 | * |
20 | * EINA_FREEQ_BYPASS=1/0 | 21 | * EINA_FREEQ_BYPASS=1/0 |
21 | * | 22 | * |
@@ -76,6 +77,48 @@ | |||
76 | */ | 77 | */ |
77 | typedef struct _Eina_FreeQ Eina_FreeQ; | 78 | typedef struct _Eina_FreeQ Eina_FreeQ; |
78 | 79 | ||
80 | /** @brief Type of free queues | ||
81 | * | ||
82 | * @since 1.19 | ||
83 | */ | ||
84 | typedef enum _Eina_FreeQ_Type | ||
85 | { | ||
86 | /** @brief Default type of free queue. | ||
87 | * | ||
88 | * Default free queue, any object added to it should be considered freed | ||
89 | * immediately. Use this kind of freeq for debugging and additional memory | ||
90 | * safety purposes only. | ||
91 | * | ||
92 | * This type of free queue is thread-safe. | ||
93 | * | ||
94 | * @since 1.19 | ||
95 | */ | ||
96 | EINA_FREEQ_DEFAULT, | ||
97 | |||
98 | /** @brief Postponed type of free queue. | ||
99 | * | ||
100 | * Postponed free queues behave differently in that objects added to it | ||
101 | * are not to be considered freed immediately, but rather they are | ||
102 | * short-lived. Use this to return temporary objects that may be used only | ||
103 | * in the local scope. The queued objects lifetime ends as soon as the | ||
104 | * execution comes back to the loop. Objects added to this kind of free | ||
105 | * queue should be accessed exclusively from the same thread that adds them. | ||
106 | * | ||
107 | * If a thread does not have a loop attached, the application may leak all | ||
108 | * those objects. At the moment of writing this means only the main loop | ||
109 | * should use such a free queue. | ||
110 | * | ||
111 | * By default those queues have no memory limit, and will be entirely | ||
112 | * flushed when the execution comes back to the loop. | ||
113 | * | ||
114 | * This type of free queue is not thread-safe and should be considered local | ||
115 | * to a single thread. | ||
116 | * | ||
117 | * @since 1.19 | ||
118 | */ | ||
119 | EINA_FREEQ_POSTPONED, | ||
120 | } Eina_FreeQ_Type; | ||
121 | |||
79 | /** | 122 | /** |
80 | * @brief Create a new free queue to defer freeing of data with | 123 | * @brief Create a new free queue to defer freeing of data with |
81 | * | 124 | * |
@@ -83,7 +126,7 @@ typedef struct _Eina_FreeQ Eina_FreeQ; | |||
83 | * @since 1.19 | 126 | * @since 1.19 |
84 | */ | 127 | */ |
85 | EAPI Eina_FreeQ * | 128 | EAPI Eina_FreeQ * |
86 | eina_freeq_new(void); | 129 | eina_freeq_new(Eina_FreeQ_Type type); |
87 | 130 | ||
88 | /** | 131 | /** |
89 | * @brief Free a free queue and anything that is queued in it. | 132 | * @brief Free a free queue and anything that is queued in it. |
@@ -96,6 +139,16 @@ EAPI void | |||
96 | eina_freeq_free(Eina_FreeQ *fq); | 139 | eina_freeq_free(Eina_FreeQ *fq); |
97 | 140 | ||
98 | /** | 141 | /** |
142 | * @brief Query the type of a free queue. | ||
143 | * | ||
144 | * @param fq The free queue to inspect. | ||
145 | * | ||
146 | * @since 1.19 | ||
147 | */ | ||
148 | EAPI Eina_FreeQ_Type | ||
149 | eina_freeq_type_get(Eina_FreeQ *fq); | ||
150 | |||
151 | /** | ||
99 | * @brief Set the main free queue driven by the EFL mainloop. | 152 | * @brief Set the main free queue driven by the EFL mainloop. |
100 | * | 153 | * |
101 | * @param fq The free queue to set as the main loop one. | 154 | * @param fq The free queue to set as the main loop one. |
@@ -119,14 +172,18 @@ eina_freeq_main_get(void); | |||
119 | * @brief Set the maximum number of free pointers this queue is allowed | 172 | * @brief Set the maximum number of free pointers this queue is allowed |
120 | * | 173 | * |
121 | * @param fq The free queue to alter | 174 | * @param fq The free queue to alter |
122 | * @param count The maximum number of items allowed (must be >= 0) | 175 | * @param count The maximum number of items allowed, negative values mean |
176 | * no limit | ||
123 | * | 177 | * |
124 | * This will alter the maximum number of pointers allowed in the given free | 178 | * This will alter the maximum number of pointers allowed in the given free |
125 | * queue. If more items are added to the free queue than are allowed, | 179 | * queue. If more items are added to the free queue than are allowed, |
126 | * excess items will be freed to make room for the new items. If count is | 180 | * excess items will be freed to make room for the new items. If count is |
127 | * changed, then excess items may be cleaned out at the time this API is | 181 | * changed, then excess items may be cleaned out at the time this API is |
128 | * called. | 182 | * called. |
129 | * | 183 | * |
184 | * @note Setting a maximum count on a postponed free queue leads to undefined | ||
185 | * behaviour. | ||
186 | * | ||
130 | * @since 1.19 | 187 | * @since 1.19 |
131 | */ | 188 | */ |
132 | EAPI void | 189 | EAPI void |
@@ -136,7 +193,7 @@ eina_freeq_count_max_set(Eina_FreeQ *fq, int count); | |||
136 | * @brief Get the maximum number of free pointers this queue is allowed | 193 | * @brief Get the maximum number of free pointers this queue is allowed |
137 | * | 194 | * |
138 | * @param fq The free queue to query | 195 | * @param fq The free queue to query |
139 | * @return The maximum number of free items allowed | 196 | * @return The maximum number of free items allowed or -1 for infinity |
140 | * | 197 | * |
141 | * @since 1.19 | 198 | * @since 1.19 |
142 | */ | 199 | */ |
@@ -156,6 +213,9 @@ eina_freeq_count_max_get(Eina_FreeQ *fq); | |||
156 | * until the total is below this limit. Changing the limit may involve | 213 | * until the total is below this limit. Changing the limit may involve |
157 | * cleaning out excess items from the free queue until the total amount of | 214 | * cleaning out excess items from the free queue until the total amount of |
158 | * memory used by items in the queue is below or at the limit. | 215 | * memory used by items in the queue is below or at the limit. |
216 | * | ||
217 | * @note Setting a memory limit on a postponed free queue leads to undefined | ||
218 | * behaviour. | ||
159 | * | 219 | * |
160 | * @since 1.19 | 220 | * @since 1.19 |
161 | */ | 221 | */ |
diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index 2f754e5360..ab0aec90b1 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c | |||
@@ -255,7 +255,7 @@ eina_init(void) | |||
255 | mtrace(); | 255 | mtrace(); |
256 | } | 256 | } |
257 | #endif | 257 | #endif |
258 | eina_freeq_main_set(eina_freeq_new()); | 258 | eina_freeq_main_set(eina_freeq_new(EINA_FREEQ_DEFAULT)); |
259 | 259 | ||
260 | if (!eina_log_init()) | 260 | if (!eina_log_init()) |
261 | { | 261 | { |
diff --git a/src/tests/eina/eina_test_freeq.c b/src/tests/eina/eina_test_freeq.c index bf732b9be0..c1d050a726 100644 --- a/src/tests/eina/eina_test_freeq.c +++ b/src/tests/eina/eina_test_freeq.c | |||
@@ -14,8 +14,9 @@ START_TEST(freeq_simple) | |||
14 | 14 | ||
15 | fail_if(eina_freeq_main_get() == NULL); | 15 | fail_if(eina_freeq_main_get() == NULL); |
16 | pfq = eina_freeq_main_get(); | 16 | pfq = eina_freeq_main_get(); |
17 | fail_if(eina_freeq_type_get(pfq) != EINA_FREEQ_DEFAULT); | ||
17 | 18 | ||
18 | fq = eina_freeq_new(); | 19 | fq = eina_freeq_new(EINA_FREEQ_DEFAULT); |
19 | fail_if(!fq); | 20 | fail_if(!fq); |
20 | 21 | ||
21 | eina_freeq_main_set(fq); | 22 | eina_freeq_main_set(fq); |
@@ -113,10 +114,91 @@ START_TEST(freeq_reduce) | |||
113 | } | 114 | } |
114 | END_TEST | 115 | END_TEST |
115 | 116 | ||
117 | static void | ||
118 | postponed_free(void *data) | ||
119 | { | ||
120 | int *p = data; | ||
121 | |||
122 | // we leak here (by choice -- to inspect the memory after clear/reduce) | ||
123 | *p = 0xDEADBEEF; | ||
124 | _n--; | ||
125 | } | ||
126 | |||
127 | static inline unsigned int * | ||
128 | new_uint(int val) | ||
129 | { | ||
130 | unsigned int *p; | ||
131 | |||
132 | p = malloc(sizeof(*p)); | ||
133 | *p = val; | ||
134 | return p; | ||
135 | } | ||
136 | |||
137 | START_TEST(freeq_postponed) | ||
138 | { | ||
139 | Eina_FreeQ *fq; | ||
140 | unsigned int *values[20]; | ||
141 | size_t k; | ||
142 | |||
143 | eina_init(); | ||
144 | _n = 0; | ||
145 | |||
146 | fq = eina_freeq_new(EINA_FREEQ_POSTPONED); | ||
147 | |||
148 | fail_if(!fq); | ||
149 | fail_if(eina_freeq_type_get(fq) != EINA_FREEQ_POSTPONED); | ||
150 | |||
151 | // by default: no limit | ||
152 | ck_assert_int_eq(eina_freeq_count_max_get(fq), -1); | ||
153 | ck_assert_int_eq(eina_freeq_mem_max_get(fq), 0); | ||
154 | |||
155 | for (k = 0; k < EINA_C_ARRAY_LENGTH(values); k++) | ||
156 | { | ||
157 | _n++; | ||
158 | values[k] = new_uint(k); | ||
159 | eina_freeq_ptr_add(fq, values[k], postponed_free, sizeof(int)); | ||
160 | } | ||
161 | ck_assert_int_eq(_n, EINA_C_ARRAY_LENGTH(values)); | ||
162 | |||
163 | fail_if(!eina_freeq_ptr_pending(fq)); | ||
164 | while (eina_freeq_ptr_pending(fq)) | ||
165 | eina_freeq_reduce(fq, 1); | ||
166 | fail_if(eina_freeq_ptr_pending(fq)); | ||
167 | ck_assert_int_eq(_n, 0); | ||
168 | |||
169 | for (k = 0; k < EINA_C_ARRAY_LENGTH(values); k++) | ||
170 | ck_assert_int_eq(*(values[k]), 0xDEADBEEF); | ||
171 | |||
172 | for (k = 0; k < EINA_C_ARRAY_LENGTH(values); k++) | ||
173 | { | ||
174 | _n++; | ||
175 | values[k] = new_uint(k); | ||
176 | eina_freeq_ptr_add(fq, values[k], postponed_free, sizeof(int)); | ||
177 | } | ||
178 | ck_assert_int_eq(_n, EINA_C_ARRAY_LENGTH(values)); | ||
179 | |||
180 | fail_if(!eina_freeq_ptr_pending(fq)); | ||
181 | eina_freeq_clear(fq); | ||
182 | fail_if(eina_freeq_ptr_pending(fq)); | ||
183 | ck_assert_int_eq(_n, 0); | ||
184 | |||
185 | for (k = 0; k < EINA_C_ARRAY_LENGTH(values); k++) | ||
186 | { | ||
187 | ck_assert_int_eq(*(values[k]), 0xDEADBEEF); | ||
188 | free(values[k]); | ||
189 | } | ||
190 | |||
191 | eina_freeq_free(fq); | ||
192 | |||
193 | eina_shutdown(); | ||
194 | } | ||
195 | END_TEST | ||
196 | |||
116 | void | 197 | void |
117 | eina_test_freeq(TCase *tc) | 198 | eina_test_freeq(TCase *tc) |
118 | { | 199 | { |
119 | tcase_add_test(tc, freeq_simple); | 200 | tcase_add_test(tc, freeq_simple); |
120 | tcase_add_test(tc, freeq_tune); | 201 | tcase_add_test(tc, freeq_tune); |
121 | tcase_add_test(tc, freeq_reduce); | 202 | tcase_add_test(tc, freeq_reduce); |
203 | tcase_add_test(tc, freeq_postponed); | ||
122 | } | 204 | } |