diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/eina/src/lib/eina_share_common.c | 977 |
1 files changed, 977 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_share_common.c b/libraries/eina/src/lib/eina_share_common.c new file mode 100644 index 0000000..90e1868 --- /dev/null +++ b/libraries/eina/src/lib/eina_share_common.c | |||
@@ -0,0 +1,977 @@ | |||
1 | /* EINA - EFL data type library | ||
2 | * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010 | ||
3 | * Carsten Haitzler, | ||
4 | * Jorge Luis Zapata Muga, | ||
5 | * Cedric Bail, | ||
6 | * Gustavo Sverzut Barbieri | ||
7 | * Tom Hacohen | ||
8 | * Brett Nash | ||
9 | * | ||
10 | * This library is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU Lesser General Public | ||
12 | * License as published by the Free Software Foundation; either | ||
13 | * version 2.1 of the License, or (at your option) any later version. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public | ||
21 | * License along with this library; | ||
22 | * if not, see <http://www.gnu.org/licenses/>. | ||
23 | * | ||
24 | * This file incorporates work covered by the following copyright and | ||
25 | * permission notice: | ||
26 | * | ||
27 | * Copyright (C) 2008 Peter Wehrfritz | ||
28 | * | ||
29 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
30 | * of this software and associated documentation files (the "Software"), to | ||
31 | * deal in the Software without restriction, including without limitation the | ||
32 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
33 | * sell copies of the Software, and to permit persons to whom the Software is | ||
34 | * furnished to do so, subject to the following conditions: | ||
35 | * | ||
36 | * The above copyright notice and this permission notice shall be included in | ||
37 | * all copies of the Software and its Copyright notices. In addition publicly | ||
38 | * documented acknowledgment must be given that this software has been used if no | ||
39 | * source code of this software is made available publicly. This includes | ||
40 | * acknowledgments in either Copyright notices, Manuals, Publicity and Marketing | ||
41 | * documents or any documentation provided with any product containing this | ||
42 | * software. This License does not apply to any software that links to the | ||
43 | * libraries provided by this software (statically or dynamically), but only to | ||
44 | * the software provided. | ||
45 | * | ||
46 | * Please see the OLD-COPYING.PLAIN for a plain-english explanation of this notice | ||
47 | * and it's intent. | ||
48 | * | ||
49 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
50 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
51 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
52 | * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
53 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
54 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
55 | */ | ||
56 | |||
57 | #ifdef HAVE_CONFIG_H | ||
58 | # include "config.h" | ||
59 | #endif | ||
60 | |||
61 | #include <stdlib.h> | ||
62 | #include <stdio.h> | ||
63 | #include <string.h> | ||
64 | #include <stddef.h> | ||
65 | |||
66 | #ifdef EFL_HAVE_POSIX_THREADS | ||
67 | # include <pthread.h> | ||
68 | #endif | ||
69 | |||
70 | #ifdef HAVE_EVIL | ||
71 | # include <Evil.h> | ||
72 | #endif | ||
73 | |||
74 | #include "eina_config.h" | ||
75 | #include "eina_private.h" | ||
76 | #include "eina_hash.h" | ||
77 | #include "eina_rbtree.h" | ||
78 | #include "eina_error.h" | ||
79 | #include "eina_log.h" | ||
80 | #include "eina_lock.h" | ||
81 | |||
82 | /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ | ||
83 | #include "eina_safety_checks.h" | ||
84 | #include "eina_share_common.h" | ||
85 | |||
86 | /*============================================================================* | ||
87 | * Local * | ||
88 | *============================================================================*/ | ||
89 | |||
90 | /** | ||
91 | * @cond LOCAL | ||
92 | */ | ||
93 | |||
94 | #define EINA_SHARE_COMMON_BUCKETS 256 | ||
95 | #define EINA_SHARE_COMMON_MASK 0xFF | ||
96 | |||
97 | static const char EINA_MAGIC_SHARE_STR[] = "Eina Share"; | ||
98 | static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head"; | ||
99 | |||
100 | static int _eina_share_common_count = 0; | ||
101 | |||
102 | #define EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(d, unlock, ...) \ | ||
103 | do { \ | ||
104 | if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_SHARE_HEAD)) \ | ||
105 | { \ | ||
106 | EINA_MAGIC_FAIL((d), EINA_MAGIC_SHARE_HEAD); \ | ||
107 | unlock; \ | ||
108 | return __VA_ARGS__; \ | ||
109 | } \ | ||
110 | } while (0) | ||
111 | |||
112 | #define EINA_MAGIC_CHECK_SHARE_COMMON_NODE(d, _node_magic, unlock) \ | ||
113 | do { \ | ||
114 | if (!EINA_MAGIC_CHECK((d), _node_magic)) \ | ||
115 | { \ | ||
116 | EINA_MAGIC_FAIL((d), _node_magic); \ | ||
117 | unlock; \ | ||
118 | } \ | ||
119 | } while (0) | ||
120 | |||
121 | #ifdef EINA_SHARE_USAGE | ||
122 | typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population; | ||
123 | #endif | ||
124 | |||
125 | typedef struct _Eina_Share_Common Eina_Share_Common; | ||
126 | typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node; | ||
127 | typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head; | ||
128 | |||
129 | int _eina_share_common_log_dom = -1; | ||
130 | |||
131 | struct _Eina_Share | ||
132 | { | ||
133 | Eina_Share_Common *share; | ||
134 | Eina_Magic node_magic; | ||
135 | #ifdef EINA_SHARE_COMMON_USAGE | ||
136 | Eina_Share_Common_Population population; | ||
137 | int max_node_population; | ||
138 | #endif | ||
139 | }; | ||
140 | |||
141 | struct _Eina_Share_Common | ||
142 | { | ||
143 | Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS]; | ||
144 | |||
145 | EINA_MAGIC | ||
146 | }; | ||
147 | |||
148 | struct _Eina_Share_Common_Node | ||
149 | { | ||
150 | Eina_Share_Common_Node *next; | ||
151 | |||
152 | EINA_MAGIC | ||
153 | |||
154 | unsigned int length; | ||
155 | unsigned int references; | ||
156 | char str[]; | ||
157 | }; | ||
158 | |||
159 | struct _Eina_Share_Common_Head | ||
160 | { | ||
161 | EINA_RBTREE; | ||
162 | EINA_MAGIC | ||
163 | |||
164 | int hash; | ||
165 | |||
166 | #ifdef EINA_SHARE_COMMON_USAGE | ||
167 | int population; | ||
168 | #endif | ||
169 | |||
170 | Eina_Share_Common_Node *head; | ||
171 | Eina_Share_Common_Node builtin_node; | ||
172 | }; | ||
173 | |||
174 | Eina_Bool _share_common_threads_activated = EINA_FALSE; | ||
175 | |||
176 | static Eina_Lock _mutex_big; | ||
177 | |||
178 | #ifdef EINA_SHARE_COMMON_USAGE | ||
179 | struct _Eina_Share_Common_Population | ||
180 | { | ||
181 | int count; | ||
182 | int max; | ||
183 | }; | ||
184 | |||
185 | static Eina_Share_Common_Population population = { 0, 0 }; | ||
186 | |||
187 | static Eina_Share_Common_Population population_group[4] = | ||
188 | { | ||
189 | { 0, 0 }, | ||
190 | { 0, 0 }, | ||
191 | { 0, 0 }, | ||
192 | { 0, 0 } | ||
193 | }; | ||
194 | |||
195 | static void | ||
196 | _eina_share_common_population_init(Eina_Share *share) | ||
197 | { | ||
198 | unsigned int i; | ||
199 | |||
200 | for (i = 0; | ||
201 | i < sizeof (share->population_group) / | ||
202 | sizeof (share->population_group[0]); | ||
203 | ++i) | ||
204 | { | ||
205 | share->population_group[i].count = 0; | ||
206 | share->population_group[i].max = 0; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | static void | ||
211 | _eina_share_common_population_shutdown(Eina_Share *share) | ||
212 | { | ||
213 | unsigned int i; | ||
214 | |||
215 | share->max_node_population = 0; | ||
216 | share->population.count = 0; | ||
217 | share->population.max = 0; | ||
218 | |||
219 | for (i = 0; | ||
220 | i < sizeof (share->population_group) / | ||
221 | sizeof (share->population_group[0]); | ||
222 | ++i) | ||
223 | { | ||
224 | share->population_group[i].count = 0; | ||
225 | share->population_group[i].max = 0; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static void | ||
230 | _eina_share_common_population_stats(Eina_Share *share) | ||
231 | { | ||
232 | unsigned int i; | ||
233 | |||
234 | fprintf(stderr, "eina share_common statistic:\n"); | ||
235 | fprintf(stderr, | ||
236 | " * maximum shared strings : %i\n", | ||
237 | share->population.max); | ||
238 | fprintf(stderr, | ||
239 | " * maximum shared strings per node : %i\n", | ||
240 | share->max_node_population); | ||
241 | |||
242 | for (i = 0; | ||
243 | i < sizeof (share->population_group) / | ||
244 | sizeof (share->population_group[0]); | ||
245 | ++i) | ||
246 | fprintf(stderr, | ||
247 | "DDD: %i strings of length %i, max strings: %i\n", | ||
248 | share->population_group[i].count, | ||
249 | i, | ||
250 | share->population_group[i].max); | ||
251 | } | ||
252 | |||
253 | void | ||
254 | eina_share_common_population_add(Eina_Share *share, int slen) | ||
255 | { | ||
256 | eina_lock_take(&_mutex_big); | ||
257 | |||
258 | share->population.count++; | ||
259 | if (share->population.count > share->population.max) | ||
260 | share->population.max = share->population.count; | ||
261 | |||
262 | if (slen < 4) | ||
263 | { | ||
264 | share->population_group[slen].count++; | ||
265 | if (share->population_group[slen].count > | ||
266 | share->population_group[slen].max) | ||
267 | share->population_group[slen].max = | ||
268 | share->population_group[slen].count; | ||
269 | } | ||
270 | |||
271 | eina_lock_release(&_mutex_big); | ||
272 | } | ||
273 | |||
274 | void | ||
275 | eina_share_common_population_del(Eina_Share *share, int slen) | ||
276 | { | ||
277 | eina_lock_take(&_mutex_big); | ||
278 | |||
279 | share->population.count--; | ||
280 | if (slen < 4) | ||
281 | share->population_group[slen].count--; | ||
282 | |||
283 | eina_lock_release(&_mutex_big); | ||
284 | } | ||
285 | |||
286 | static void | ||
287 | _eina_share_common_population_head_init(Eina_Share *share, | ||
288 | Eina_Share_Common_Head *head) | ||
289 | { | ||
290 | head->population = 1; | ||
291 | } | ||
292 | |||
293 | static void | ||
294 | _eina_share_common_population_head_add(Eina_Share *share, | ||
295 | Eina_Share_Common_Head *head) | ||
296 | { | ||
297 | head->population++; | ||
298 | if (head->population > share->max_node_population) | ||
299 | share->max_node_population = head->population; | ||
300 | } | ||
301 | |||
302 | static void | ||
303 | _eina_share_common_population_head_del(Eina_Share *share, | ||
304 | Eina_Share_Common_Head *head) | ||
305 | { | ||
306 | head->population--; | ||
307 | } | ||
308 | |||
309 | #else /* EINA_SHARE_COMMON_USAGE undefined */ | ||
310 | |||
311 | static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) { | ||
312 | } | ||
313 | static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share *share) | ||
314 | { | ||
315 | } | ||
316 | static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) { | ||
317 | } | ||
318 | void eina_share_common_population_add(__UNUSED__ Eina_Share *share, | ||
319 | __UNUSED__ int slen) { | ||
320 | } | ||
321 | void eina_share_common_population_del(__UNUSED__ Eina_Share *share, | ||
322 | __UNUSED__ int slen) { | ||
323 | } | ||
324 | static void _eina_share_common_population_head_init( | ||
325 | __UNUSED__ Eina_Share *share, | ||
326 | __UNUSED__ Eina_Share_Common_Head *head) { | ||
327 | } | ||
328 | static void _eina_share_common_population_head_add( | ||
329 | __UNUSED__ Eina_Share *share, | ||
330 | __UNUSED__ | ||
331 | Eina_Share_Common_Head *head) { | ||
332 | } | ||
333 | static void _eina_share_common_population_head_del( | ||
334 | __UNUSED__ Eina_Share *share, | ||
335 | __UNUSED__ | ||
336 | Eina_Share_Common_Head *head) { | ||
337 | } | ||
338 | #endif | ||
339 | |||
340 | static int | ||
341 | _eina_share_common_cmp(const Eina_Share_Common_Head *ed, | ||
342 | const int *hash, | ||
343 | __UNUSED__ int length, | ||
344 | __UNUSED__ void *data) | ||
345 | { | ||
346 | EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0); | ||
347 | |||
348 | return ed->hash - *hash; | ||
349 | } | ||
350 | |||
351 | static Eina_Rbtree_Direction | ||
352 | _eina_share_common_node(const Eina_Share_Common_Head *left, | ||
353 | const Eina_Share_Common_Head *right, | ||
354 | __UNUSED__ void *data) | ||
355 | { | ||
356 | EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left, , 0); | ||
357 | EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0); | ||
358 | |||
359 | if (left->hash - right->hash < 0) | ||
360 | return EINA_RBTREE_LEFT; | ||
361 | |||
362 | return EINA_RBTREE_RIGHT; | ||
363 | } | ||
364 | |||
365 | static void | ||
366 | _eina_share_common_head_free(Eina_Share_Common_Head *ed, __UNUSED__ void *data) | ||
367 | { | ||
368 | EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, ); | ||
369 | |||
370 | while (ed->head) | ||
371 | { | ||
372 | Eina_Share_Common_Node *el = ed->head; | ||
373 | |||
374 | ed->head = ed->head->next; | ||
375 | if (el != &ed->builtin_node) | ||
376 | MAGIC_FREE(el); | ||
377 | } | ||
378 | MAGIC_FREE(ed); | ||
379 | } | ||
380 | |||
381 | static void | ||
382 | _eina_share_common_node_init(Eina_Share_Common_Node *node, | ||
383 | const char *str, | ||
384 | int slen, | ||
385 | unsigned int null_size, | ||
386 | Eina_Magic node_magic) | ||
387 | { | ||
388 | EINA_MAGIC_SET(node, node_magic); | ||
389 | node->references = 1; | ||
390 | node->length = slen; | ||
391 | memcpy(node->str, str, slen); | ||
392 | memset(node->str + slen, 0, null_size); /* Nullify the null */ | ||
393 | |||
394 | (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */ | ||
395 | } | ||
396 | |||
397 | static Eina_Share_Common_Head * | ||
398 | _eina_share_common_head_alloc(int slen) | ||
399 | { | ||
400 | Eina_Share_Common_Head *head; | ||
401 | const size_t head_size = offsetof(Eina_Share_Common_Head, builtin_node.str); | ||
402 | |||
403 | head = malloc(head_size + slen); | ||
404 | if (!head) | ||
405 | eina_error_set(EINA_ERROR_OUT_OF_MEMORY); | ||
406 | |||
407 | return head; | ||
408 | } | ||
409 | |||
410 | static const char * | ||
411 | _eina_share_common_add_head(Eina_Share *share, | ||
412 | Eina_Share_Common_Head **p_bucket, | ||
413 | int hash, | ||
414 | const char *str, | ||
415 | unsigned int slen, | ||
416 | unsigned int null_size) | ||
417 | { | ||
418 | Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket; | ||
419 | Eina_Share_Common_Head *head; | ||
420 | |||
421 | head = _eina_share_common_head_alloc(slen + null_size); | ||
422 | if (!head) | ||
423 | return NULL; | ||
424 | |||
425 | EINA_MAGIC_SET(head, EINA_MAGIC_SHARE_HEAD); | ||
426 | head->hash = hash; | ||
427 | head->head = &head->builtin_node; | ||
428 | _eina_share_common_node_init(head->head, | ||
429 | str, | ||
430 | slen, | ||
431 | null_size, | ||
432 | share->node_magic); | ||
433 | head->head->next = NULL; | ||
434 | |||
435 | _eina_share_common_population_head_init(share, head); | ||
436 | |||
437 | *p_tree = eina_rbtree_inline_insert | ||
438 | (*p_tree, EINA_RBTREE_GET(head), | ||
439 | EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL); | ||
440 | |||
441 | return head->head->str; | ||
442 | } | ||
443 | |||
444 | static void | ||
445 | _eina_share_common_del_head(Eina_Share_Common_Head **p_bucket, | ||
446 | Eina_Share_Common_Head *head) | ||
447 | { | ||
448 | Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket; | ||
449 | |||
450 | *p_tree = eina_rbtree_inline_remove | ||
451 | (*p_tree, EINA_RBTREE_GET(head), | ||
452 | EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL); | ||
453 | |||
454 | MAGIC_FREE(head); | ||
455 | } | ||
456 | |||
457 | |||
458 | static inline Eina_Bool | ||
459 | _eina_share_common_node_eq(const Eina_Share_Common_Node *node, | ||
460 | const char *str, | ||
461 | unsigned int slen) | ||
462 | { | ||
463 | return ((node->length == slen) && | ||
464 | (memcmp(node->str, str, slen) == 0)); | ||
465 | } | ||
466 | |||
467 | static Eina_Share_Common_Node * | ||
468 | _eina_share_common_head_find(Eina_Share_Common_Head *head, | ||
469 | const char *str, | ||
470 | unsigned int slen) | ||
471 | { | ||
472 | Eina_Share_Common_Node *node, *prev; | ||
473 | |||
474 | node = head->head; | ||
475 | if (_eina_share_common_node_eq(node, str, slen)) | ||
476 | return node; | ||
477 | |||
478 | prev = node; | ||
479 | node = node->next; | ||
480 | for (; node; prev = node, node = node->next) | ||
481 | if (_eina_share_common_node_eq(node, str, slen)) | ||
482 | { | ||
483 | /* promote node, make hot items be at the beginning */ | ||
484 | prev->next = node->next; | ||
485 | node->next = head->head; | ||
486 | head->head = node; | ||
487 | return node; | ||
488 | } | ||
489 | |||
490 | return NULL; | ||
491 | } | ||
492 | |||
493 | static Eina_Bool | ||
494 | _eina_share_common_head_remove_node(Eina_Share_Common_Head *head, | ||
495 | const Eina_Share_Common_Node *node) | ||
496 | { | ||
497 | Eina_Share_Common_Node *cur, *prev; | ||
498 | |||
499 | if (head->head == node) | ||
500 | { | ||
501 | head->head = node->next; | ||
502 | return 1; | ||
503 | } | ||
504 | |||
505 | prev = head->head; | ||
506 | cur = head->head->next; | ||
507 | for (; cur; prev = cur, cur = cur->next) | ||
508 | if (cur == node) | ||
509 | { | ||
510 | prev->next = cur->next; | ||
511 | return 1; | ||
512 | } | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static Eina_Share_Common_Head * | ||
518 | _eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash) | ||
519 | { | ||
520 | return (Eina_Share_Common_Head *)eina_rbtree_inline_lookup | ||
521 | (EINA_RBTREE_GET(bucket), &hash, 0, | ||
522 | EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL); | ||
523 | } | ||
524 | |||
525 | static Eina_Share_Common_Node * | ||
526 | _eina_share_common_node_alloc(unsigned int slen, unsigned int null_size) | ||
527 | { | ||
528 | Eina_Share_Common_Node *node; | ||
529 | const size_t node_size = offsetof(Eina_Share_Common_Node, str); | ||
530 | |||
531 | node = malloc(node_size + slen + null_size); | ||
532 | if (!node) | ||
533 | eina_error_set(EINA_ERROR_OUT_OF_MEMORY); | ||
534 | |||
535 | return node; | ||
536 | } | ||
537 | |||
538 | static Eina_Share_Common_Node * | ||
539 | _eina_share_common_node_from_str(const char *str, Eina_Magic node_magic) | ||
540 | { | ||
541 | Eina_Share_Common_Node *node; | ||
542 | const size_t offset = offsetof(Eina_Share_Common_Node, str); | ||
543 | |||
544 | node = (Eina_Share_Common_Node *)(str - offset); | ||
545 | EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL); | ||
546 | return node; | ||
547 | |||
548 | (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */ | ||
549 | } | ||
550 | |||
551 | static Eina_Bool | ||
552 | eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__, | ||
553 | Eina_Share_Common_Head *head, | ||
554 | struct dumpinfo *fdata) | ||
555 | { | ||
556 | Eina_Share_Common_Node *node; | ||
557 | |||
558 | fdata->used += sizeof(Eina_Share_Common_Head); | ||
559 | for (node = head->head; node; node = node->next) | ||
560 | { | ||
561 | printf("DDD: %5i %5i ", node->length, node->references); | ||
562 | printf("'%.*s'\n", node->length, ((char *)node) + sizeof(Eina_Share_Common_Node)); | ||
563 | fdata->used += sizeof(Eina_Share_Common_Node); | ||
564 | fdata->used += node->length; | ||
565 | fdata->saved += (node->references - 1) * node->length; | ||
566 | fdata->dups += node->references - 1; | ||
567 | fdata->unique++; | ||
568 | } | ||
569 | |||
570 | return EINA_TRUE; | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * @endcond | ||
575 | */ | ||
576 | |||
577 | |||
578 | /*============================================================================* | ||
579 | * Global * | ||
580 | *============================================================================*/ | ||
581 | |||
582 | /** | ||
583 | * @internal | ||
584 | * @brief Initialize the share_common module. | ||
585 | * | ||
586 | * @return #EINA_TRUE on success, #EINA_FALSE on failure. | ||
587 | * | ||
588 | * This function sets up the share_common module of Eina. It is called by | ||
589 | * eina_init(). | ||
590 | * | ||
591 | * @see eina_init() | ||
592 | */ | ||
593 | Eina_Bool | ||
594 | eina_share_common_init(Eina_Share **_share, | ||
595 | Eina_Magic node_magic, | ||
596 | const char *node_magic_STR) | ||
597 | { | ||
598 | Eina_Share *share; | ||
599 | |||
600 | share = *_share = calloc(sizeof(Eina_Share), 1); | ||
601 | if (!share) goto on_error; | ||
602 | |||
603 | if (_eina_share_common_log_dom < 0) /*Only register if not already */ | ||
604 | _eina_share_common_log_dom = eina_log_domain_register( | ||
605 | "eina_share", | ||
606 | EINA_LOG_COLOR_DEFAULT); | ||
607 | |||
608 | if (_eina_share_common_log_dom < 0) | ||
609 | { | ||
610 | EINA_LOG_ERR("Could not register log domain: eina_share_common"); | ||
611 | goto on_error; | ||
612 | } | ||
613 | |||
614 | share->share = calloc(1, sizeof(Eina_Share_Common)); | ||
615 | if (!share->share) | ||
616 | { | ||
617 | if (_eina_share_common_log_dom > 0) | ||
618 | { | ||
619 | eina_log_domain_unregister(_eina_share_common_log_dom); | ||
620 | _eina_share_common_log_dom = -1; | ||
621 | } | ||
622 | |||
623 | goto on_error; | ||
624 | } | ||
625 | |||
626 | share->node_magic = node_magic; | ||
627 | #define EMS(n) eina_magic_string_static_set(n, n ## _STR) | ||
628 | EMS(EINA_MAGIC_SHARE); | ||
629 | EMS(EINA_MAGIC_SHARE_HEAD); | ||
630 | EMS(node_magic); | ||
631 | #undef EMS | ||
632 | EINA_MAGIC_SET(share->share, EINA_MAGIC_SHARE); | ||
633 | |||
634 | _eina_share_common_population_init(share); | ||
635 | |||
636 | /* below is the common part among other all eina_share_common user */ | ||
637 | if (_eina_share_common_count++ != 0) | ||
638 | return EINA_TRUE; | ||
639 | |||
640 | eina_lock_new(&_mutex_big); | ||
641 | return EINA_TRUE; | ||
642 | |||
643 | on_error: | ||
644 | _eina_share_common_count--; | ||
645 | return EINA_FALSE; | ||
646 | } | ||
647 | |||
648 | /** | ||
649 | * @internal | ||
650 | * @brief Shut down the share_common module. | ||
651 | * | ||
652 | * @return #EINA_TRUE on success, #EINA_FALSE on failure. | ||
653 | * | ||
654 | * This function shuts down the share_common module set up by | ||
655 | * eina_share_common_init(). It is called by eina_shutdown(). | ||
656 | * | ||
657 | * @see eina_shutdown() | ||
658 | */ | ||
659 | Eina_Bool | ||
660 | eina_share_common_shutdown(Eina_Share **_share) | ||
661 | { | ||
662 | unsigned int i; | ||
663 | Eina_Share *share = *_share; | ||
664 | |||
665 | eina_lock_take(&_mutex_big); | ||
666 | |||
667 | _eina_share_common_population_stats(share); | ||
668 | |||
669 | /* remove any string still in the table */ | ||
670 | for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++) | ||
671 | { | ||
672 | eina_rbtree_delete(EINA_RBTREE_GET( | ||
673 | share->share->buckets[i]), | ||
674 | EINA_RBTREE_FREE_CB( | ||
675 | _eina_share_common_head_free), NULL); | ||
676 | share->share->buckets[i] = NULL; | ||
677 | } | ||
678 | MAGIC_FREE(share->share); | ||
679 | |||
680 | _eina_share_common_population_shutdown(share); | ||
681 | if (_eina_share_common_log_dom > 0) /* Only free if necessary */ | ||
682 | { | ||
683 | eina_log_domain_unregister(_eina_share_common_log_dom); | ||
684 | _eina_share_common_log_dom = -1; | ||
685 | } | ||
686 | |||
687 | eina_lock_release(&_mutex_big); | ||
688 | |||
689 | free(*_share); | ||
690 | *_share = NULL; | ||
691 | |||
692 | /* below is the common part among other all eina_share_common user */ | ||
693 | if (--_eina_share_common_count != 0) | ||
694 | return EINA_TRUE; | ||
695 | |||
696 | eina_lock_free(&_mutex_big); | ||
697 | |||
698 | return EINA_TRUE; | ||
699 | } | ||
700 | |||
701 | #ifdef EFL_HAVE_THREADS | ||
702 | |||
703 | /** | ||
704 | * @internal | ||
705 | * @brief Activate the share_common mutexes. | ||
706 | * | ||
707 | * This function activate the mutexes in the eina share_common module. It is called by | ||
708 | * eina_threads_init(). | ||
709 | * | ||
710 | * @see eina_threads_init() | ||
711 | */ | ||
712 | void | ||
713 | eina_share_common_threads_init(void) | ||
714 | { | ||
715 | _share_common_threads_activated = EINA_TRUE; | ||
716 | } | ||
717 | |||
718 | /** | ||
719 | * @internal | ||
720 | * @brief Shut down the share_common mutexes. | ||
721 | * | ||
722 | * This function shuts down the mutexes in the share_common module. | ||
723 | * It is called by eina_threads_shutdown(). | ||
724 | * | ||
725 | * @see eina_threads_shutdown() | ||
726 | */ | ||
727 | void | ||
728 | eina_share_common_threads_shutdown(void) | ||
729 | { | ||
730 | _share_common_threads_activated = EINA_FALSE; | ||
731 | } | ||
732 | |||
733 | #endif | ||
734 | |||
735 | /*============================================================================* | ||
736 | * API * | ||
737 | *============================================================================*/ | ||
738 | |||
739 | /** | ||
740 | * @cond LOCAL | ||
741 | */ | ||
742 | |||
743 | const char * | ||
744 | eina_share_common_add_length(Eina_Share *share, | ||
745 | const char *str, | ||
746 | unsigned int slen, | ||
747 | unsigned int null_size) | ||
748 | { | ||
749 | Eina_Share_Common_Head **p_bucket, *ed; | ||
750 | Eina_Share_Common_Node *el; | ||
751 | int hash_num, hash; | ||
752 | |||
753 | if (!str) | ||
754 | return NULL; | ||
755 | |||
756 | eina_share_common_population_add(share, slen); | ||
757 | |||
758 | if (slen <= 0) | ||
759 | return NULL; | ||
760 | |||
761 | hash = eina_hash_superfast(str, slen); | ||
762 | hash_num = hash & 0xFF; | ||
763 | hash = (hash >> 8) & EINA_SHARE_COMMON_MASK; | ||
764 | |||
765 | eina_lock_take(&_mutex_big); | ||
766 | p_bucket = share->share->buckets + hash_num; | ||
767 | |||
768 | ed = _eina_share_common_find_hash(*p_bucket, hash); | ||
769 | if (!ed) | ||
770 | { | ||
771 | const char *s = _eina_share_common_add_head(share, | ||
772 | p_bucket, | ||
773 | hash, | ||
774 | str, | ||
775 | slen, | ||
776 | null_size); | ||
777 | eina_lock_release(&_mutex_big); | ||
778 | return s; | ||
779 | } | ||
780 | |||
781 | EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), NULL); | ||
782 | |||
783 | el = _eina_share_common_head_find(ed, str, slen); | ||
784 | if (el) | ||
785 | { | ||
786 | EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el, | ||
787 | share->node_magic, | ||
788 | eina_lock_release(&_mutex_big)); | ||
789 | el->references++; | ||
790 | eina_lock_release(&_mutex_big); | ||
791 | return el->str; | ||
792 | } | ||
793 | |||
794 | el = _eina_share_common_node_alloc(slen, null_size); | ||
795 | if (!el) | ||
796 | { | ||
797 | eina_lock_release(&_mutex_big); | ||
798 | return NULL; | ||
799 | } | ||
800 | |||
801 | _eina_share_common_node_init(el, str, slen, null_size, share->node_magic); | ||
802 | el->next = ed->head; | ||
803 | ed->head = el; | ||
804 | _eina_share_common_population_head_add(share, ed); | ||
805 | |||
806 | eina_lock_release(&_mutex_big); | ||
807 | |||
808 | return el->str; | ||
809 | } | ||
810 | |||
811 | const char * | ||
812 | eina_share_common_ref(Eina_Share *share, const char *str) | ||
813 | { | ||
814 | Eina_Share_Common_Node *node; | ||
815 | |||
816 | if (!str) | ||
817 | return NULL; | ||
818 | |||
819 | eina_lock_take(&_mutex_big); | ||
820 | node = _eina_share_common_node_from_str(str, share->node_magic); | ||
821 | if (!node) | ||
822 | { | ||
823 | eina_lock_release(&_mutex_big); | ||
824 | return str; | ||
825 | } | ||
826 | node->references++; | ||
827 | |||
828 | eina_lock_release(&_mutex_big); | ||
829 | |||
830 | eina_share_common_population_add(share, node->length); | ||
831 | |||
832 | return str; | ||
833 | } | ||
834 | |||
835 | |||
836 | void | ||
837 | eina_share_common_del(Eina_Share *share, const char *str) | ||
838 | { | ||
839 | unsigned int slen; | ||
840 | Eina_Share_Common_Head *ed; | ||
841 | Eina_Share_Common_Head **p_bucket; | ||
842 | Eina_Share_Common_Node *node; | ||
843 | int hash_num, hash; | ||
844 | |||
845 | if (!str) | ||
846 | return; | ||
847 | |||
848 | eina_lock_take(&_mutex_big); | ||
849 | |||
850 | node = _eina_share_common_node_from_str(str, share->node_magic); | ||
851 | if (!node) | ||
852 | goto on_error; | ||
853 | |||
854 | slen = node->length; | ||
855 | eina_share_common_population_del(share, slen); | ||
856 | if (node->references > 1) | ||
857 | { | ||
858 | node->references--; | ||
859 | eina_lock_release(&_mutex_big); | ||
860 | return; | ||
861 | } | ||
862 | |||
863 | node->references = 0; | ||
864 | |||
865 | hash = eina_hash_superfast(str, slen); | ||
866 | hash_num = hash & 0xFF; | ||
867 | hash = (hash >> 8) & EINA_SHARE_COMMON_MASK; | ||
868 | |||
869 | p_bucket = share->share->buckets + hash_num; | ||
870 | ed = _eina_share_common_find_hash(*p_bucket, hash); | ||
871 | if (!ed) | ||
872 | goto on_error; | ||
873 | |||
874 | EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big)); | ||
875 | |||
876 | if (!_eina_share_common_head_remove_node(ed, node)) | ||
877 | goto on_error; | ||
878 | |||
879 | if (node != &ed->builtin_node) | ||
880 | MAGIC_FREE(node); | ||
881 | |||
882 | if (!ed->head) | ||
883 | _eina_share_common_del_head(p_bucket, ed); | ||
884 | else | ||
885 | _eina_share_common_population_head_del(share, ed); | ||
886 | |||
887 | eina_lock_release(&_mutex_big); | ||
888 | |||
889 | return; | ||
890 | |||
891 | on_error: | ||
892 | eina_lock_release(&_mutex_big); | ||
893 | /* possible segfault happened before here, but... */ | ||
894 | CRITICAL("EEEK trying to del non-shared share_common \"%s\"", str); | ||
895 | } | ||
896 | |||
897 | int | ||
898 | eina_share_common_length(__UNUSED__ Eina_Share *share, const char *str) | ||
899 | { | ||
900 | const Eina_Share_Common_Node *node; | ||
901 | |||
902 | if (!str) | ||
903 | return -1; | ||
904 | |||
905 | node = _eina_share_common_node_from_str(str, share->node_magic); | ||
906 | if (!node) return 0; | ||
907 | return node->length; | ||
908 | } | ||
909 | |||
910 | void | ||
911 | eina_share_common_dump(Eina_Share *share, void (*additional_dump)( | ||
912 | struct dumpinfo *), int used) | ||
913 | { | ||
914 | Eina_Iterator *it; | ||
915 | unsigned int i; | ||
916 | struct dumpinfo di; | ||
917 | |||
918 | if (!share) | ||
919 | return; | ||
920 | |||
921 | di.used = used; | ||
922 | di.saved = 0; | ||
923 | di.dups = 0; | ||
924 | di.unique = 0; | ||
925 | printf("DDD: len ref string\n"); | ||
926 | printf("DDD:-------------------\n"); | ||
927 | |||
928 | eina_lock_take(&_mutex_big); | ||
929 | for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++) | ||
930 | { | ||
931 | if (!share->share->buckets[i]) | ||
932 | { | ||
933 | continue; // printf("DDD: BUCKET # %i (HEAD=%i, NODE=%i)\n", i, | ||
934 | |||
935 | } | ||
936 | |||
937 | // sizeof(Eina_Share_Common_Head), sizeof(Eina_Share_Common_Node)); | ||
938 | it = eina_rbtree_iterator_prefix( | ||
939 | (Eina_Rbtree *)share->share->buckets[i]); | ||
940 | eina_iterator_foreach(it, EINA_EACH_CB(eina_iterator_array_check), &di); | ||
941 | eina_iterator_free(it); | ||
942 | } | ||
943 | if (additional_dump) | ||
944 | additional_dump(&di); | ||
945 | |||
946 | #ifdef EINA_SHARE_COMMON_USAGE | ||
947 | /* One character strings are not counted in the hash. */ | ||
948 | di.saved += share->population_group[0].count * sizeof(char); | ||
949 | di.saved += share->population_group[1].count * sizeof(char) * 2; | ||
950 | #endif | ||
951 | printf("DDD:-------------------\n"); | ||
952 | printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n", | ||
953 | di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0); | ||
954 | printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n", | ||
955 | di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0); | ||
956 | |||
957 | #ifdef EINA_SHARE_COMMON_USAGE | ||
958 | printf("DDD: Allocated strings: %i\n", share->population.count); | ||
959 | printf("DDD: Max allocated strings: %i\n", share->population.max); | ||
960 | |||
961 | for (i = 0; | ||
962 | i < sizeof (share->population_group) / | ||
963 | sizeof (share->population_group[0]); | ||
964 | ++i) | ||
965 | fprintf(stderr, | ||
966 | "DDD: %i strings of length %i, max strings: %i\n", | ||
967 | share->population_group[i].count, | ||
968 | i, | ||
969 | share->population_group[i].max); | ||
970 | #endif | ||
971 | |||
972 | eina_lock_release(&_mutex_big); | ||
973 | } | ||
974 | |||
975 | /** | ||
976 | * @endcond | ||
977 | */ | ||