1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "Eina.h"
10 #include "eina_private.h"
11 
12 #ifdef HAVE_VALGRIND
13 # include <valgrind.h>
14 # include <memcheck.h>
15 #endif
16 
17 // ========================================================================= //
18 
19 #define ITEM_FILLPAT_MAX 0
20 #define ITEM_TOTAL_MAX   ( 256 * 1024)
21 #define ITEM_MEM_MAX     (  32 * 1024 * 1024)
22 #if __WORDSIZE == 32
23 // 4kb blocks
24 //# define ITEM_BLOCK_COUNT 340
25 // 64k blocks
26 # define ITEM_BLOCK_COUNT 5459
27 // 256k blocks
28 //# define ITEM_BLOCK_COUNT 21844
29 #else // __WORDSIZE == 64
30 // 4kb blocks
31 //# define ITEM_BLOCK_COUNT 170
32 // 64k blocks
33 # define ITEM_BLOCK_COUNT 2730
34 // 256k blocks
35 //# define ITEM_BLOCK_COUNT 10922
36 #endif
37 
38 // ========================================================================= //
39 
40 typedef struct _Eina_FreeQ_Item Eina_FreeQ_Item;
41 typedef struct _Eina_FreeQ_Block Eina_FreeQ_Block;
42 
43 // ========================================================================= //
44 
45 // these items are highly compressable. here is a dump of F: ptr freefunc size
46 // ...
47 // F: 0xaaab0454dd00 0xffff8b83b628 0x10
48 // F: 0xaaab0454bd00 0xffff8b83b648 0x20
49 // F: 0xaaab0454dd10 0xffff8b83b628 0x10
50 // F: 0xaaab0454bd20 0xffff8b83b648 0x20
51 // F: 0xaaab0454dd20 0xffff8b83b628 0x10
52 // F: 0xaaab0454bd40 0xffff8b83b648 0x20
53 // F: 0xaaab0454dd30 0xffff8b83b628 0x10
54 // F: 0xaaab0454bd60 0xffff8b83b648 0x20
55 // F: 0xaaab0454bda0 0xffff8b83b648 0x20
56 // F: 0xaaab0454bdc0 0xffff8b83b648 0x20
57 // ...
58 // F: 0xaaab049176d0 0xffff8b83b648 0x20
59 // F: 0xaaab04917750 0xffff8b83b648 0x20
60 // F: 0xaaab04917770 0xffff8b83b648 0x20
61 // F: 0xaaab04917330 0xffff8b83b648 0x20
62 // F: 0xaaab0481b3c0 0xffff8b83b628 0x10
63 // F: 0xaaab049177f0 0xffff8b83b648 0x20
64 // F: 0xaaab049259a0 0xffff8af1c638 0x38
65 // F: 0xaaab049172d0 0xffff8b83b648 0x20
66 // F: 0xaaab049172f0 0xffff8b83b648 0x20
67 // F: 0xaaab04925c00 0xffff8af1c638 0x38
68 // F: 0xaaab04925c40 0xffff8af1c638 0x38
69 // F: 0xaaab0481b3b0 0xffff8b83b628 0x10
70 // F: 0xaaab04917310 0xffff8b83b648 0x20
71 // F: 0xaaab04925bc0 0xffff8af1c638 0x38
72 // F: 0xaaab0491d240 0xffff8af1c638 0x40
73 // F: 0xaaab0492b3a0 0xffff8af1c638 0x38
74 // F: 0xaaab049225c0 0xffff8af1c638 (nil)
75 // F: 0xaaab04917730 0xffff8b83b648 0x20
76 // F: 0xaaab04917790 0xffff8b83b648 0x20
77 // F: 0xaaab049177b0 0xffff8b83b648 0x20
78 // F: 0xaaab0492b710 0xffff8af1c638 0x38
79 // F: 0xaaab0492b750 0xffff8af1c638 0x38
80 // F: 0xaaab0481b420 0xffff8b83b628 0x10
81 // F: 0xaaab049177d0 0xffff8b83b648 0x20
82 // F: 0xaaab0492b2d0 0xffff8af1c638 0x38
83 // F: 0xaaab0481b410 0xffff8b83b628 0x10
84 // F: 0xaaab04917710 0xffff8b83b648 0x20
85 // F: 0xaaab0492b280 0xffff8af1c638 0x40
86 // F: 0xaaab0481b430 0xffff8b83b628 0x10
87 // F: 0xaaab04917810 0xffff8b83b648 0x20
88 // F: 0xaaab0492b6d0 0xffff8af1c638 0x38
89 // F: 0xaaab0491ca80 0xffff8af1c638 (nil)
90 // F: 0xaaab0492b350 0xffff8af1c638 0x40
91 // F: 0xaaab0490fef0 0xffff8af1c638 0x38
92 // F: 0xaaab0481b320 0xffff8b83b628 0x10
93 // F: 0xaaab04916ff0 0xffff8b83b648 0x20
94 // F: 0xaaab0481b330 0xffff8b83b628 0x10
95 // F: 0xaaab04917030 0xffff8b83b648 0x20
96 // F: 0xaaab04920560 0xffff8af1c638 0x38
97 // F: 0xaaab0481b350 0xffff8b83b628 0x10
98 // F: 0xaaab049170f0 0xffff8b83b648 0x20
99 // F: 0xaaab04917050 0xffff8b83b648 0x20
100 // F: 0xaaab04920510 0xffff8af1c638 0x40
101 // F: 0xaaab04920850 0xffff8af1c638 0x38
102 // F: 0xaaab04917070 0xffff8b83b648 0x20
103 // F: 0xaaab04920800 0xffff8af1c638 0x40
104 // F: 0xaaab04920c30 0xffff8af1c638 0x38
105 // F: 0xaaab04917090 0xffff8b83b648 0x20
106 // F: 0xaaab04920be0 0xffff8af1c638 0x40
107 // F: 0xaaab04920e60 0xffff8af1c638 0x38
108 // F: 0xaaab04920e10 0xffff8af1c638 0x40
109 // F: 0xaaab049212b0 0xffff8af1c638 0x38
110 // F: 0xaaab0481b340 0xffff8b83b628 0x10
111 // F: 0xaaab049170d0 0xffff8b83b648 0x20
112 // F: 0xaaab04921260 0xffff8af1c638 0x40
113 // F: 0xaaab0481b1f0 0xffff8b83b628 0x10
114 // F: 0xaaab04875d50 0xffff8b83b648 0x20
115 // F: 0xaaab0490fea0 0xffff8af1c638 0x40
116 // F: 0xaaab049102e0 0xffff8af1c638 0x38
117 // F: 0xaaab04917010 0xffff8b83b648 0x20
118 // F: 0xaaab0490b4f0 0xffff8af1c638 (nil)
119 // F: 0xaaab04910290 0xffff8af1c638 0x40
120 // F: 0xaaab0481b460 0xffff8b83b628 0x10
121 // F: 0xaaab049178b0 0xffff8b83b648 0x20
122 // F: 0xaaab0481b450 0xffff8b83b628 0x10
123 // F: 0xaaab04917870 0xffff8b83b648 0x20
124 // F: 0xaaab0481b490 0xffff8b83b628 0x10
125 // F: 0xaaab049e56f0 0xffff8b83b648 0x20
126 // F: 0xaaab0481b4a0 0xffff8b83b628 0x10
127 // F: 0xaaab049e5710 0xffff8b83b648 0x20
128 // F: 0xaaab0481b4b0 0xffff8b83b628 0x10
129 // F: 0xaaab049e5730 0xffff8b83b648 0x20
130 // F: 0xaaab0481b4c0 0xffff8b83b628 0x10
131 // F: 0xaaab049e5750 0xffff8b83b648 0x20
132 // F: 0xaaab0481b4f0 0xffff8b83b628 0x10
133 // F: 0xaaab049e57d0 0xffff8b83b648 0x20
134 // F: 0xaaab049e5990 0xffff8b83b648 0x20
135 // F: 0xaaab049e5770 0xffff8b83b648 0x20
136 // F: 0xaaab0481b4d0 0xffff8b83b628 0x10
137 // F: 0xaaab049e5790 0xffff8b83b648 0x20
138 // F: 0xaaab049e5a50 0xffff8b83b648 0x20
139 // F: 0xaaab049e57b0 0xffff8b83b648 0x20
140 // ...
141 // F: 0xaaab04d9f330 0xffff8b83b648 0x20
142 // F: 0xaaab04b18920 0xffff8b83b628 0x10
143 // F: 0xaaab04d9f350 0xffff8b83b648 0x20
144 // F: 0xaaab04d4d000 0xffff8b83b648 0x20
145 // F: 0xaaab04d9f370 0xffff8b83b648 0x20
146 // F: 0xaaab04d9f390 0xffff8b83b648 0x20
147 // F: 0xaaab04d9f3b0 0xffff8b83b648 0x20
148 // F: 0xaaab04b18930 0xffff8b83b628 0x10
149 // F: 0xaaab04d9f3d0 0xffff8b83b648 0x20
150 // F: 0xaaab04d9f3f0 0xffff8b83b648 0x20
151 // F: 0xaaab04d9f410 0xffff8b83b648 0x20
152 // F: 0xaaab04d9f430 0xffff8b83b648 0x20
153 // F: 0xaaab04b18940 0xffff8b83b628 0x10
154 // F: 0xaaab04d9f450 0xffff8b83b648 0x20
155 // F: 0xaaab04d4d020 0xffff8b83b648 0x20
156 // F: 0xaaab04d9f470 0xffff8b83b648 0x20
157 // F: 0xaaab04d9f490 0xffff8b83b648 0x20
158 // F: 0xaaab04d9f4b0 0xffff8b83b648 0x20
159 // F: 0xaaab04b18950 0xffff8b83b628 0x10
160 // F: 0xaaab04d9f4d0 0xffff8b83b648 0x20
161 // F: 0xaaab04d9f4f0 0xffff8b83b648 0x20
162 // F: 0xaaab04d9f510 0xffff8b83b648 0x20
163 // F: 0xaaab04d9f530 0xffff8b83b648 0x20
164 // F: 0xaaab04b18960 0xffff8b83b628 0x10
165 // F: 0xaaab04d9f550 0xffff8b83b648 0x20
166 // F: 0xaaab04640ce0 0xffff8b83b628 0x10
167 // F: 0xaaab04d9ee10 0xffff8b83b648 0x20
168 // F: 0xaaab04577e50 0xffff8af1c638 (nil)
169 // F: 0xaaab04571570 0xffff8af1c638 (nil)
170 // F: 0xaaab04577ee0 0xffff8af1c638 0x40
171 // F: 0xaaab0457af50 0xffff8af1c638 (nil)
172 // F: 0xaaab04571590 0xffff8af1c638 (nil)
173 // F: 0xaaab0457afe0 0xffff8af1c638 0x40
174 // F: 0xaaab0457e0c0 0xffff8af1c638 (nil)
175 // F: 0xaaab0457b360 0xffff8af1c638 (nil)
176 // F: 0xaaab0457e150 0xffff8af1c638 0x40
177 // F: 0xaaab04581860 0xffff8af1c638 (nil)
178 // F: 0xaaab04581330 0xffff8af1c638 (nil)
179 // F: 0xaaab045818f0 0xffff8af1c638 0x40
180 // F: 0xaaab0490ed00 0xffff8af1c638 0xc0
181 // F: 0xaaab0490f090 0xffff8af1c638 0xc0
182 // F: 0xaaab04922760 0xffff8af1c638 0xc0
183 // F: 0xaaab04922880 0xffff8af1c638 0xc0
184 // F: 0xaaab04922a20 0xffff8af1c638 0xc0
185 // F: 0xaaab0491cb80 0xffff8af1c638 0xc0
186 // F: 0xaaab0492b8e0 0xffff8af1c638 0xc0
187 // F: 0xaaab0492c4b0 0xffff8af1c638 0xc0
188 // F: 0xaaab0492c5c0 0xffff8af1c638 0xc0
189 // F: 0xaaab0492c750 0xffff8af1c638 0xc0
190 // F: 0xaaab04926230 0xffff8af1c638 0xc0
191 // F: 0xaaab04920d00 0xffff8af1c638 0xc0
192 // F: 0xaaab04920aa0 0xffff8af1c638 0xc0
193 // F: 0xaaab04a05280 0xffff8af1c638 0xc0
194 // F: 0xaaab04a053d0 0xffff8af1c638 0xc0
195 // F: 0xaaab04a05520 0xffff8af1c638 0xc0
196 // F: 0xaaab049f3860 0xffff8af1c638 0xc0
197 // F: 0xaaab049f3a30 0xffff8af1c638 0xc0
198 // F: 0xaaab04a06e60 0xffff8af1c638 0xc0
199 // F: 0xaaab04a25490 0xffff8af1c638 0xc0
200 // F: 0xaaab04a55170 0xffff8af1c638 0xc0
201 // F: 0xaaab04a55ca0 0xffff8af1c638 0xc0
202 // ...
203 // so in future maybe create delta compression. keep a "start value" in the
204 // Eina_FreeQ_Block block for each to begin from (and update these as we
205 // march blcok->start forward (or at least update them when we finish a run
206 // of processing items at the end of the processing.
207 //
208 // we can store things as DELTAS from the preview value. ptr, func, size all
209 // are ptr sized values so we can compress them with deltas and thus encode
210 // them in variable runs of bytes depending on the size of the delta. e.g.
211 // use LEB128 maybe or PrefixVariant.
212 //
213 // after some playng leb128 seems to be the best from simplicity (so fast
214 // encode which matters and decode needs to be good too) and size. i saw
215 // a reduction to 24% of the original data size this way based on the sample
216 // data i collected like above. is it worth the extra cycles? don't know.
217 //
218 // when looking at the deltas i noticed that func and sie delats are very
219 // often 0 for long runs. this means we can probably use RLE effectively
220 // if we split this into 3 streams wahc delta compressed then RLE compressed
221 // per stream. walking is more complex and filling the block means taking
222 // a guess at pre-allocating offsets per stream so it may not fill the blocks
223 // as affectively then. again - is it worth it? need to measure if RLE helps
224 // a lot or not in keeping size down in addition to delta + leb128.
225 struct _Eina_FreeQ_Item
226 {
227    void    *ptr;
228    void   (*free_func) (void *ptr);
229    size_t  size;
230 };
231 
232 struct _Eina_FreeQ_Block
233 {
234    int start;
235    int end;
236    Eina_FreeQ_Block *next;
237    Eina_FreeQ_Item items[ITEM_BLOCK_COUNT];
238 };
239 
240 struct _Eina_FreeQ
241 {
242    Eina_Lock lock; // recursive lock, unused for postponed queues (thread-local)
243    int count; // number of item slots used
244    int count_max; // maximum number of slots allowed to be used or -1
245    size_t mem_max; // the maximum amount of memory allowed to be used
246    size_t mem_total; // current total memory known about in the queue
247    Eina_FreeQ_Block *blocks; // the list of blocks of free items
248    Eina_FreeQ_Block *block_last; // the last block to append items to
249    Eina_Bool bypass; // 0 if not to bypass, 1 if we should bypass
250    Eina_Bool postponed; // 1 if postponed type of freeq (eg. temp strings)
251    Eina_Bool unlocked; // 0 by default, 1 if thread-local (lock not used)
252 };
253 
254 // ========================================================================= //
255 
256 static Eina_FreeQ    *_eina_freeq_main              = NULL;
257 static int            _eina_freeq_bypass            = -1;
258 static unsigned int   _eina_freeq_fillpat_max       = ITEM_FILLPAT_MAX;
259 static unsigned char  _eina_freeq_fillpat_val       = 0x55;
260 static unsigned char  _eina_freeq_fillpat_freed_val = 0x77;
261 static int            _eina_freeq_total_max         = ITEM_TOTAL_MAX;
262 static size_t         _eina_freeq_mem_max           = ITEM_MEM_MAX;
263 
264 // debgging/tuning info to enable in future when gathering stats
265 #if 0
266 static int            _max_seen = 0;
267 # define FQMAX(fq) \
268    if (fq == _eina_freeq_main) { \
269       if (fq->count > _max_seen) { \
270          _max_seen = fq->count; \
271          printf("FQ max: %i\n", _max_seen); \
272       } \
273    }
274 #else
275 # define FQMAX(fq)
276 #endif
277 
278 // ========================================================================= //
279 
280 #define LOCK_FQ(fq); do { \
281    if (!fq->unlocked) eina_lock_take(&(fq->lock)); } while(0)
282 #define UNLOCK_FQ(fq); do { \
283    if (!fq->unlocked) eina_lock_release(&(fq->lock)); } while(0)
284 
285 // ========================================================================= //
286 
287 static inline void
_eina_freeq_fill_do(void * ptr,size_t size)288 _eina_freeq_fill_do(void *ptr, size_t size)
289 {
290    if (ptr) memset(ptr, _eina_freeq_fillpat_val, size);
291 }
292 
293 static inline void
_eina_freeq_freed_fill_do(void * ptr,size_t size)294 _eina_freeq_freed_fill_do(void *ptr, size_t size)
295 {
296    if (_eina_freeq_fillpat_freed_val == 0) return;
297    if (ptr) memset(ptr, _eina_freeq_fillpat_freed_val, size);
298 }
299 
300 static void
_eina_freeq_fill_check(void * ptr,void (* free_func)(void * ptr),size_t size)301 _eina_freeq_fill_check(void *ptr, void (*free_func) (void *ptr), size_t size)
302 {
303    unsigned char *p0 = ptr, *p = p0, *pe = p + size;
304    for (; p < pe; p++)
305      {
306         if (*p != _eina_freeq_fillpat_val) goto err;
307      }
308    return;
309 err:
310    EINA_LOG_ERR("Pointer %p size %lu freed by %p has fill error %x != %x @ %lu",
311                 p0, (unsigned long)size, free_func,
312                 (unsigned int)*p, (unsigned int)_eina_freeq_fillpat_val,
313                 (unsigned long)(p - p0));
314 }
315 
316 static void
_eina_freeq_free_do(void * ptr,void (* free_func)(void * ptr),size_t size)317 _eina_freeq_free_do(void *ptr,
318                     void (*free_func) (void *ptr),
319                     size_t size)
320 {
321    if (EINA_LIKELY((size > 0) && (size < _eina_freeq_fillpat_max)))
322      {
323         _eina_freeq_fill_check(ptr, free_func, size);
324         _eina_freeq_freed_fill_do(ptr, size);
325      }
326    free_func(ptr);
327    return;
328 }
329 
330 static Eina_Bool
_eina_freeq_block_append(Eina_FreeQ * fq)331 _eina_freeq_block_append(Eina_FreeQ *fq)
332 {
333    Eina_FreeQ_Block *fb = malloc(sizeof(Eina_FreeQ_Block));
334    if (!fb) return EINA_FALSE;
335    fb->start = 0;
336    fb->end = 0;
337    fb->next = NULL;
338    if (!fq->blocks) fq->blocks = fb;
339    else fq->block_last->next = fb;
340    fq->block_last = fb;
341    return EINA_TRUE;
342 }
343 
344 static void
_eina_freeq_process(Eina_FreeQ * fq)345 _eina_freeq_process(Eina_FreeQ *fq)
346 {
347    Eina_FreeQ_Block *fb = fq->blocks;
348    if (!fb) return;
349    _eina_freeq_free_do(fb->items[fb->start].ptr,
350                        fb->items[fb->start].free_func,
351                        fb->items[fb->start].size);
352    fq->mem_total -= fb->items[fb->start].size;
353    fb->start++;
354    fq->count--;
355    if (fb->start == fb->end)
356      {
357         fq->blocks = fb->next;
358         if (!fq->blocks) fq->block_last = NULL;
359         free(fb);
360      }
361 }
362 
363 static void
_eina_freeq_flush_nolock(Eina_FreeQ * fq)364 _eina_freeq_flush_nolock(Eina_FreeQ *fq)
365 {
366    if (fq->postponed) return;
367 
368    FQMAX(fq);
369    while ((fq->count > fq->count_max) || (fq->mem_total > fq->mem_max))
370      _eina_freeq_process(fq);
371 }
372 
373 // ========================================================================= //
374 
375 static Eina_FreeQ *
_eina_freeq_new_default(void)376 _eina_freeq_new_default(void)
377 {
378    Eina_FreeQ *fq;
379 
380    if (EINA_UNLIKELY(_eina_freeq_bypass == -1))
381      {
382         const char *s;
383         int v;
384 
385         s = getenv("EINA_FREEQ_BYPASS");
386         if (s)
387           {
388              v = atoi(s);
389              if (v == 0) _eina_freeq_bypass = 0;
390              else _eina_freeq_bypass = 1;
391           }
392         if (_eina_freeq_bypass == -1)
393           {
394 #ifdef HAVE_VALGRIND
395              if (RUNNING_ON_VALGRIND) _eina_freeq_bypass = 1;
396              else
397 #endif
398                _eina_freeq_bypass = 0;
399           }
400         s = getenv("EINA_FREEQ_FILL_MAX");
401         if (s) _eina_freeq_fillpat_max = atoi(s);
402         s = getenv("EINA_FREEQ_TOTAL_MAX");
403         if (s) _eina_freeq_total_max = atoi(s);
404         s = getenv("EINA_FREEQ_MEM_MAX");
405         if (s) _eina_freeq_mem_max = atoi(s) * 1024;
406         s = getenv("EINA_FREEQ_FILL");
407         if (s) _eina_freeq_fillpat_val = atoi(s);
408         s = getenv("EINA_FREEQ_FILL_FREED");
409         if (s) _eina_freeq_fillpat_freed_val = atoi(s);
410      }
411    fq = calloc(1, sizeof(Eina_FreeQ));
412    if (!fq) return NULL;
413    eina_lock_recursive_new(&(fq->lock));
414    fq->count_max = _eina_freeq_total_max;
415    fq->mem_max = _eina_freeq_mem_max;
416    fq->bypass = _eina_freeq_bypass;
417    return fq;
418 }
419 
420 static Eina_FreeQ *
_eina_freeq_new_postponed(void)421 _eina_freeq_new_postponed(void)
422 {
423    Eina_FreeQ *fq;
424 
425    fq= calloc(1, sizeof(*fq));
426    if (!fq) return NULL;
427    fq->mem_max = 0;
428    fq->count_max = -1;
429    fq->postponed = EINA_TRUE;
430    fq->unlocked = EINA_TRUE;
431    return fq;
432 }
433 
434 EAPI Eina_FreeQ *
eina_freeq_new(Eina_FreeQ_Type type)435 eina_freeq_new(Eina_FreeQ_Type type)
436 {
437    switch (type)
438      {
439       case EINA_FREEQ_DEFAULT:
440         return _eina_freeq_new_default();
441       case EINA_FREEQ_POSTPONED:
442         return _eina_freeq_new_postponed();
443       default:
444         return NULL;
445      }
446 }
447 
448 EAPI void
eina_freeq_free(Eina_FreeQ * fq)449 eina_freeq_free(Eina_FreeQ *fq)
450 {
451    if (!fq) return;
452    if (fq == _eina_freeq_main) _eina_freeq_main = NULL;
453    eina_freeq_clear(fq);
454    if (!fq->unlocked) eina_lock_free(&(fq->lock));
455    free(fq);
456 }
457 
458 EAPI Eina_FreeQ_Type
eina_freeq_type_get(Eina_FreeQ * fq)459 eina_freeq_type_get(Eina_FreeQ *fq)
460 {
461    if (fq && fq->postponed)
462      return EINA_FREEQ_POSTPONED;
463    return EINA_FREEQ_DEFAULT;
464 }
465 
466 void
eina_freeq_main_set(Eina_FreeQ * fq)467 eina_freeq_main_set(Eina_FreeQ *fq)
468 {
469    if (!fq) return;
470    _eina_freeq_main = fq;
471 }
472 
473 EAPI Eina_FreeQ *
eina_freeq_main_get(void)474 eina_freeq_main_get(void)
475 {
476    return _eina_freeq_main;
477 }
478 
479 EAPI void
eina_freeq_count_max_set(Eina_FreeQ * fq,int count)480 eina_freeq_count_max_set(Eina_FreeQ *fq, int count)
481 {
482    if (!fq) return;
483    if (fq->postponed) return;
484    if (count < 0) count = -1;
485    LOCK_FQ(fq);
486    fq->bypass = 0;
487    fq->count_max = count;
488    _eina_freeq_flush_nolock(fq);
489    UNLOCK_FQ(fq);
490 }
491 
492 EAPI int
eina_freeq_count_max_get(Eina_FreeQ * fq)493 eina_freeq_count_max_get(Eina_FreeQ *fq)
494 {
495    int count;
496 
497    if (!fq) return 0;
498    LOCK_FQ(fq);
499    if (fq->bypass) count = 0;
500    else count = fq->count_max;
501    UNLOCK_FQ(fq);
502    return count;
503 }
504 
505 EAPI void
eina_freeq_mem_max_set(Eina_FreeQ * fq,size_t mem)506 eina_freeq_mem_max_set(Eina_FreeQ *fq, size_t mem)
507 {
508    if (!fq) return;
509    if (fq->postponed) return;
510    LOCK_FQ(fq);
511    fq->bypass = 0;
512    fq->mem_max = mem;
513    _eina_freeq_flush_nolock(fq);
514    UNLOCK_FQ(fq);
515 }
516 
517 EAPI size_t
eina_freeq_mem_max_get(Eina_FreeQ * fq)518 eina_freeq_mem_max_get(Eina_FreeQ *fq)
519 {
520    size_t mem;
521 
522    if (!fq) return 0;
523    LOCK_FQ(fq);
524    if (fq->bypass) mem = 0;
525    else mem = fq->mem_max;
526    UNLOCK_FQ(fq);
527    return mem;
528 }
529 
530 EAPI void
eina_freeq_clear(Eina_FreeQ * fq)531 eina_freeq_clear(Eina_FreeQ *fq)
532 {
533    if (!fq) return;
534    LOCK_FQ(fq);
535    FQMAX(fq);
536    while (fq->count > 0) _eina_freeq_process(fq);
537    UNLOCK_FQ(fq);
538 }
539 
540 EAPI void
eina_freeq_reduce(Eina_FreeQ * fq,int count)541 eina_freeq_reduce(Eina_FreeQ *fq, int count)
542 {
543    if (!fq) return;
544    LOCK_FQ(fq);
545    FQMAX(fq);
546    while ((fq->count > 0) && (count > 0))
547      {
548         _eina_freeq_process(fq);
549         count--;
550      }
551    UNLOCK_FQ(fq);
552 }
553 
554 EAPI Eina_Bool
eina_freeq_ptr_pending(Eina_FreeQ * fq)555 eina_freeq_ptr_pending(Eina_FreeQ *fq)
556 {
557    Eina_Bool pending;
558 
559    if (!fq) return EINA_FALSE;
560    LOCK_FQ(fq);
561    if (fq->blocks) pending = EINA_TRUE;
562    else pending = EINA_FALSE;
563    UNLOCK_FQ(fq);
564    return pending;
565 }
566 
567 EAPI void
eina_freeq_ptr_add(Eina_FreeQ * fq,void * ptr,void (* free_func)(void * ptr),size_t size)568 eina_freeq_ptr_add(Eina_FreeQ *fq,
569                    void *ptr,
570                    void (*free_func) (void *ptr),
571                    size_t size)
572 {
573    Eina_FreeQ_Block *fb;
574 
575    if (!ptr) return;
576    if (!free_func) free_func = free;
577    if ((((fq) && !fq->postponed) || (!fq)) &&
578        (size < _eina_freeq_fillpat_max) && (size > 0))
579      _eina_freeq_fill_do(ptr, size);
580 
581    if (!fq || fq->bypass)
582      {
583         _eina_freeq_free_do(ptr, free_func, size);
584         return;
585      }
586 
587    LOCK_FQ(fq);
588    if ((!fq->block_last) || (fq->block_last->end == ITEM_BLOCK_COUNT))
589      {
590         if (!_eina_freeq_block_append(fq))
591           {
592              UNLOCK_FQ(fq);
593              if (!fq->postponed)
594                _eina_freeq_free_do(ptr, free_func, size);
595              else
596                EINA_LOG_ERR("Could not add a pointer to the free queue! This "
597                             "program will leak resources!");
598              return;
599           }
600      }
601 
602    fb = fq->block_last;
603    fb->items[fb->end].ptr = ptr;
604    fb->items[fb->end].free_func = free_func;
605    fb->items[fb->end].size = size;
606    fb->end++;
607    fq->count++;
608    fq->mem_total += size;
609    _eina_freeq_flush_nolock(fq);
610    UNLOCK_FQ(fq);
611 }
612