1 /* EINA - EFL data type library
2 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
4 * Jorge Luis Zapata Muga,
6 * Gustavo Sverzut Barbieri
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.
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.
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/>.
24 * This file incorporates work covered by the following copyright and
27 * Copyright (C) 2008 Peter Wehrfritz
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:
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.
46 * Please see the OLD-COPYING.PLAIN for a plain-english explanation of this notice
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.
66 #ifdef EFL_HAVE_POSIX_THREADS
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_lock.h"
81 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
82 #include "eina_safety_checks.h"
83 #include "eina_share_common.h"
85 /*============================================================================*
87 *============================================================================*/
93 #define EINA_SHARE_COMMON_BUCKETS 256
94 #define EINA_SHARE_COMMON_MASK 0xFF
96 static const char EINA_MAGIC_SHARE_STR[] = "Eina Share";
97 static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head";
99 static int _eina_share_common_count = 0;
101 #define EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(d, unlock, ...) \
103 if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_SHARE_HEAD)) \
105 EINA_MAGIC_FAIL((d), EINA_MAGIC_SHARE_HEAD); \
107 return __VA_ARGS__; \
111 #define EINA_MAGIC_CHECK_SHARE_COMMON_NODE(d, _node_magic, unlock) \
113 if (!EINA_MAGIC_CHECK((d), _node_magic)) \
115 EINA_MAGIC_FAIL((d), _node_magic); \
120 #ifdef EINA_SHARE_USAGE
121 typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population;
124 typedef struct _Eina_Share_Common Eina_Share_Common;
125 typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node;
126 typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head;
130 Eina_Share_Common *share;
131 Eina_Magic node_magic;
132 #ifdef EINA_SHARE_COMMON_USAGE
133 Eina_Share_Common_Population population;
134 int max_node_population;
138 struct _Eina_Share_Common
140 Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS];
145 struct _Eina_Share_Common_Node
147 Eina_Share_Common_Node *next;
152 unsigned int references;
156 struct _Eina_Share_Common_Head
163 #ifdef EINA_SHARE_COMMON_USAGE
167 Eina_Share_Common_Node *head;
168 Eina_Share_Common_Node builtin_node;
171 Eina_Bool _share_common_threads_activated = EINA_FALSE;
173 static Eina_Lock _mutex_big;
175 #ifdef EINA_SHARE_COMMON_USAGE
176 struct _Eina_Share_Common_Population
182 static Eina_Share_Common_Population population = { 0, 0 };
184 static Eina_Share_Common_Population population_group[4] =
193 _eina_share_common_population_init(Eina_Share *share)
198 i < sizeof (share->population_group) /
199 sizeof (share->population_group[0]);
202 share->population_group[i].count = 0;
203 share->population_group[i].max = 0;
208 _eina_share_common_population_shutdown(Eina_Share *share)
212 share->max_node_population = 0;
213 share->population.count = 0;
214 share->population.max = 0;
217 i < sizeof (share->population_group) /
218 sizeof (share->population_group[0]);
221 share->population_group[i].count = 0;
222 share->population_group[i].max = 0;
227 _eina_share_common_population_stats(Eina_Share *share)
231 fprintf(stderr, "eina share_common statistic:\n");
233 " * maximum shared strings : %i\n",
234 share->population.max);
236 " * maximum shared strings per node : %i\n",
237 share->max_node_population);
240 i < sizeof (share->population_group) /
241 sizeof (share->population_group[0]);
244 "DDD: %i strings of length %i, max strings: %i\n",
245 share->population_group[i].count,
247 share->population_group[i].max);
251 eina_share_common_population_add(Eina_Share *share, int slen)
253 eina_lock_take(&_mutex_big);
255 share->population.count++;
256 if (share->population.count > share->population.max)
257 share->population.max = share->population.count;
261 share->population_group[slen].count++;
262 if (share->population_group[slen].count >
263 share->population_group[slen].max)
264 share->population_group[slen].max =
265 share->population_group[slen].count;
268 eina_lock_release(&_mutex_big);
272 eina_share_common_population_del(Eina_Share *share, int slen)
274 eina_lock_take(&_mutex_big);
276 share->population.count--;
278 share->population_group[slen].count--;
280 eina_lock_release(&_mutex_big);
284 _eina_share_common_population_head_init(Eina_Share *share,
285 Eina_Share_Common_Head *head)
287 head->population = 1;
291 _eina_share_common_population_head_add(Eina_Share *share,
292 Eina_Share_Common_Head *head)
295 if (head->population > share->max_node_population)
296 share->max_node_population = head->population;
300 _eina_share_common_population_head_del(Eina_Share *share,
301 Eina_Share_Common_Head *head)
306 #else /* EINA_SHARE_COMMON_USAGE undefined */
308 static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) {
310 static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share *share)
313 static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) {
315 void eina_share_common_population_add(__UNUSED__ Eina_Share *share,
316 __UNUSED__ int slen) {
318 void eina_share_common_population_del(__UNUSED__ Eina_Share *share,
319 __UNUSED__ int slen) {
321 static void _eina_share_common_population_head_init(
322 __UNUSED__ Eina_Share *share,
323 __UNUSED__ Eina_Share_Common_Head *head) {
325 static void _eina_share_common_population_head_add(
326 __UNUSED__ Eina_Share *share,
328 Eina_Share_Common_Head *head) {
330 static void _eina_share_common_population_head_del(
331 __UNUSED__ Eina_Share *share,
333 Eina_Share_Common_Head *head) {
338 _eina_share_common_cmp(const Eina_Share_Common_Head *ed,
340 __UNUSED__ int length,
341 __UNUSED__ void *data)
343 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0);
345 return ed->hash - *hash;
348 static Eina_Rbtree_Direction
349 _eina_share_common_node(const Eina_Share_Common_Head *left,
350 const Eina_Share_Common_Head *right,
351 __UNUSED__ void *data)
353 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left, , 0);
354 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0);
356 if (left->hash - right->hash < 0)
357 return EINA_RBTREE_LEFT;
359 return EINA_RBTREE_RIGHT;
363 _eina_share_common_head_free(Eina_Share_Common_Head *ed, __UNUSED__ void *data)
365 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, );
369 Eina_Share_Common_Node *el = ed->head;
371 ed->head = ed->head->next;
372 if (el != &ed->builtin_node)
379 _eina_share_common_node_init(Eina_Share_Common_Node *node,
382 unsigned int null_size,
383 Eina_Magic node_magic)
385 EINA_MAGIC_SET(node, node_magic);
386 node->references = 1;
388 memcpy(node->str, str, slen);
389 memset(node->str + slen, 0, null_size); /* Nullify the null */
391 (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
394 static Eina_Share_Common_Head *
395 _eina_share_common_head_alloc(int slen)
397 Eina_Share_Common_Head *head;
398 const size_t head_size = offsetof(Eina_Share_Common_Head, builtin_node.str);
400 head = malloc(head_size + slen);
402 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
408 _eina_share_common_add_head(Eina_Share *share,
409 Eina_Share_Common_Head **p_bucket,
413 unsigned int null_size)
415 Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
416 Eina_Share_Common_Head *head;
418 head = _eina_share_common_head_alloc(slen + null_size);
422 EINA_MAGIC_SET(head, EINA_MAGIC_SHARE_HEAD);
424 head->head = &head->builtin_node;
425 _eina_share_common_node_init(head->head,
430 head->head->next = NULL;
432 _eina_share_common_population_head_init(share, head);
434 *p_tree = eina_rbtree_inline_insert
435 (*p_tree, EINA_RBTREE_GET(head),
436 EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
438 return head->head->str;
442 _eina_share_common_del_head(Eina_Share_Common_Head **p_bucket,
443 Eina_Share_Common_Head *head)
445 Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
447 *p_tree = eina_rbtree_inline_remove
448 (*p_tree, EINA_RBTREE_GET(head),
449 EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
455 static inline Eina_Bool
456 _eina_share_common_node_eq(const Eina_Share_Common_Node *node,
460 return ((node->length == slen) &&
461 (memcmp(node->str, str, slen) == 0));
464 static Eina_Share_Common_Node *
465 _eina_share_common_head_find(Eina_Share_Common_Head *head,
469 Eina_Share_Common_Node *node, *prev;
472 if (_eina_share_common_node_eq(node, str, slen))
477 for (; node; prev = node, node = node->next)
478 if (_eina_share_common_node_eq(node, str, slen))
480 /* promote node, make hot items be at the beginning */
481 prev->next = node->next;
482 node->next = head->head;
491 _eina_share_common_head_remove_node(Eina_Share_Common_Head *head,
492 const Eina_Share_Common_Node *node)
494 Eina_Share_Common_Node *cur, *prev;
496 if (head->head == node)
498 head->head = node->next;
503 cur = head->head->next;
504 for (; cur; prev = cur, cur = cur->next)
507 prev->next = cur->next;
514 static Eina_Share_Common_Head *
515 _eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash)
517 return (Eina_Share_Common_Head *)eina_rbtree_inline_lookup
518 (EINA_RBTREE_GET(bucket), &hash, 0,
519 EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL);
522 static Eina_Share_Common_Node *
523 _eina_share_common_node_alloc(unsigned int slen, unsigned int null_size)
525 Eina_Share_Common_Node *node;
526 const size_t node_size = offsetof(Eina_Share_Common_Node, str);
528 node = malloc(node_size + slen + null_size);
530 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
535 static Eina_Share_Common_Node *
536 _eina_share_common_node_from_str(const char *str, Eina_Magic node_magic)
538 Eina_Share_Common_Node *node;
539 const size_t offset = offsetof(Eina_Share_Common_Node, str);
541 node = (Eina_Share_Common_Node *)(str - offset);
542 EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL);
545 (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
549 eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__,
550 Eina_Share_Common_Head *head,
551 struct dumpinfo *fdata)
553 Eina_Share_Common_Node *node;
555 fdata->used += sizeof(Eina_Share_Common_Head);
556 for (node = head->head; node; node = node->next)
558 printf("DDD: %5i %5i ", node->length, node->references);
559 printf("'%.*s'\n", node->length, ((char *)node) + sizeof(Eina_Share_Common_Node));
560 fdata->used += sizeof(Eina_Share_Common_Node);
561 fdata->used += node->length;
562 fdata->saved += (node->references - 1) * node->length;
563 fdata->dups += node->references - 1;
575 /*============================================================================*
577 *============================================================================*/
581 * @brief Initialize the share_common module.
583 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
585 * This function sets up the share_common module of Eina. It is called by
591 eina_share_common_init(Eina_Share **_share,
592 Eina_Magic node_magic,
593 const char *node_magic_STR)
597 share = *_share = calloc(sizeof(Eina_Share), 1);
598 if (!share) goto on_error;
600 share->share = calloc(1, sizeof(Eina_Share_Common));
601 if (!share->share) goto on_error;
603 share->node_magic = node_magic;
604 #define EMS(n) eina_magic_string_static_set(n, n ## _STR)
605 EMS(EINA_MAGIC_SHARE);
606 EMS(EINA_MAGIC_SHARE_HEAD);
609 EINA_MAGIC_SET(share->share, EINA_MAGIC_SHARE);
611 _eina_share_common_population_init(share);
613 /* below is the common part among other all eina_share_common user */
614 if (_eina_share_common_count++ != 0)
617 eina_lock_new(&_mutex_big);
621 _eina_share_common_count--;
627 * @brief Shut down the share_common module.
629 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
631 * This function shuts down the share_common module set up by
632 * eina_share_common_init(). It is called by eina_shutdown().
634 * @see eina_shutdown()
637 eina_share_common_shutdown(Eina_Share **_share)
640 Eina_Share *share = *_share;
642 eina_lock_take(&_mutex_big);
644 _eina_share_common_population_stats(share);
646 /* remove any string still in the table */
647 for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
649 eina_rbtree_delete(EINA_RBTREE_GET(
650 share->share->buckets[i]),
652 _eina_share_common_head_free), NULL);
653 share->share->buckets[i] = NULL;
655 MAGIC_FREE(share->share);
657 _eina_share_common_population_shutdown(share);
659 eina_lock_release(&_mutex_big);
664 /* below is the common part among other all eina_share_common user */
665 if (--_eina_share_common_count != 0)
668 eina_lock_free(&_mutex_big);
673 #ifdef EFL_HAVE_THREADS
677 * @brief Activate the share_common mutexes.
679 * This function activate the mutexes in the eina share_common module. It is called by
680 * eina_threads_init().
682 * @see eina_threads_init()
685 eina_share_common_threads_init(void)
687 _share_common_threads_activated = EINA_TRUE;
692 * @brief Shut down the share_common mutexes.
694 * This function shuts down the mutexes in the share_common module.
695 * It is called by eina_threads_shutdown().
697 * @see eina_threads_shutdown()
700 eina_share_common_threads_shutdown(void)
702 _share_common_threads_activated = EINA_FALSE;
707 /*============================================================================*
709 *============================================================================*/
716 eina_share_common_add_length(Eina_Share *share,
719 unsigned int null_size)
721 Eina_Share_Common_Head **p_bucket, *ed;
722 Eina_Share_Common_Node *el;
728 eina_share_common_population_add(share, slen);
733 hash = eina_hash_superfast(str, slen);
734 hash_num = hash & 0xFF;
735 hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
737 eina_lock_take(&_mutex_big);
738 p_bucket = share->share->buckets + hash_num;
740 ed = _eina_share_common_find_hash(*p_bucket, hash);
743 const char *s = _eina_share_common_add_head(share,
749 eina_lock_release(&_mutex_big);
753 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), NULL);
755 el = _eina_share_common_head_find(ed, str, slen);
758 EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el,
760 eina_lock_release(&_mutex_big));
762 eina_lock_release(&_mutex_big);
766 el = _eina_share_common_node_alloc(slen, null_size);
769 eina_lock_release(&_mutex_big);
773 _eina_share_common_node_init(el, str, slen, null_size, share->node_magic);
776 _eina_share_common_population_head_add(share, ed);
778 eina_lock_release(&_mutex_big);
784 eina_share_common_ref(Eina_Share *share, const char *str)
786 Eina_Share_Common_Node *node;
791 eina_lock_take(&_mutex_big);
792 node = _eina_share_common_node_from_str(str, share->node_magic);
795 eina_lock_release(&_mutex_big);
800 eina_lock_release(&_mutex_big);
802 eina_share_common_population_add(share, node->length);
809 eina_share_common_del(Eina_Share *share, const char *str)
812 Eina_Share_Common_Head *ed;
813 Eina_Share_Common_Head **p_bucket;
814 Eina_Share_Common_Node *node;
820 eina_lock_take(&_mutex_big);
822 node = _eina_share_common_node_from_str(str, share->node_magic);
827 eina_share_common_population_del(share, slen);
828 if (node->references > 1)
831 eina_lock_release(&_mutex_big);
835 node->references = 0;
837 hash = eina_hash_superfast(str, slen);
838 hash_num = hash & 0xFF;
839 hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
841 p_bucket = share->share->buckets + hash_num;
842 ed = _eina_share_common_find_hash(*p_bucket, hash);
846 EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), EINA_FALSE);
848 if (!_eina_share_common_head_remove_node(ed, node))
851 if (node != &ed->builtin_node)
855 _eina_share_common_del_head(p_bucket, ed);
857 _eina_share_common_population_head_del(share, ed);
859 eina_lock_release(&_mutex_big);
864 eina_lock_release(&_mutex_big);
865 /* possible segfault happened before here, but... */
870 eina_share_common_length(__UNUSED__ Eina_Share *share, const char *str)
872 const Eina_Share_Common_Node *node;
877 node = _eina_share_common_node_from_str(str, share->node_magic);
883 eina_share_common_dump(Eina_Share *share, void (*additional_dump)(
884 struct dumpinfo *), int used)
897 printf("DDD: len ref string\n");
898 printf("DDD:-------------------\n");
900 eina_lock_take(&_mutex_big);
901 for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
903 if (!share->share->buckets[i])
905 continue; // printf("DDD: BUCKET # %i (HEAD=%i, NODE=%i)\n", i,
909 // sizeof(Eina_Share_Common_Head), sizeof(Eina_Share_Common_Node));
910 it = eina_rbtree_iterator_prefix(
911 (Eina_Rbtree *)share->share->buckets[i]);
912 eina_iterator_foreach(it, EINA_EACH_CB(eina_iterator_array_check), &di);
913 eina_iterator_free(it);
916 additional_dump(&di);
918 #ifdef EINA_SHARE_COMMON_USAGE
919 /* One character strings are not counted in the hash. */
920 di.saved += share->population_group[0].count * sizeof(char);
921 di.saved += share->population_group[1].count * sizeof(char) * 2;
923 printf("DDD:-------------------\n");
924 printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n",
925 di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0);
926 printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n",
927 di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0);
929 #ifdef EINA_SHARE_COMMON_USAGE
930 printf("DDD: Allocated strings: %i\n", share->population.count);
931 printf("DDD: Max allocated strings: %i\n", share->population.max);
934 i < sizeof (share->population_group) /
935 sizeof (share->population_group[0]);
938 "DDD: %i strings of length %i, max strings: %i\n",
939 share->population_group[i].count,
941 share->population_group[i].max);
944 eina_lock_release(&_mutex_big);