eo: Turn thread-validation off for unstable Tizen 5.0 apps which are violating thread...
[platform/upstream/efl.git] / src / lib / eo / eo_ptr_indirection.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include "eo_ptr_indirection.h"
6
7 extern Eina_Thread _efl_object_main_thread;
8
9 //////////////////////////////////////////////////////////////////////////
10
11 Eina_TLS          _eo_table_data;
12 Eo_Id_Data       *_eo_table_data_shared = NULL;
13 Eo_Id_Table_Data *_eo_table_data_shared_data = NULL;
14
15 /* TIZEN_ONLY(20180518): See _eo_table_data_get() in eo_ptr_indirection.x. */
16 #ifdef DISABLE_EO_THREAD_CHECK
17 Eo_Id_Data       *_tizen_eo_table_data = NULL;
18 #endif
19
20 //////////////////////////////////////////////////////////////////////////
21
22 void
23 _eo_pointer_error(const Eo *obj_id, const char *func_name, const char *file, int line, const char *fmt, ...)
24 {
25    /* NOTE: this function exists to allow easy breakpoint on pointer errors */
26    va_list args;
27    va_start(args, fmt);
28    eina_log_vprint(_eo_log_dom, EINA_LOG_LEVEL_ERR, file, func_name, line, fmt, args);
29    va_end(args);
30    _eo_log_obj_report((Eo_Id)obj_id, EINA_LOG_LEVEL_ERR, func_name, file, line);
31 }
32
33 static void
34 _eo_obj_pointer_invalid(const Eo_Id obj_id,
35                         Eo_Id_Data *data,
36                         unsigned char domain,
37                         const char *func_name,
38                         const char *file,
39                         int line)
40 {
41    Eina_Thread thread = eina_thread_self();
42    const char *tself = "main";
43    const char *type = "object";
44    const char *reason = "This ID has probably been deleted";
45    char tbuf[128];
46    if (obj_id & MASK_CLASS_TAG) type = "class";
47    if (thread != _efl_object_main_thread)
48      {
49         snprintf(tbuf, sizeof(tbuf), "%p", (void *)thread);
50         tself = tbuf;
51      }
52
53    if (!data->tables[(int)data->local_domain])
54      reason = "This ID does not seem to belong to this thread";
55    else if ((Efl_Id_Domain)domain == EFL_ID_DOMAIN_SHARED)
56      reason = "This shared ID has probably been deleted";
57
58    eina_log_print(_eo_log_dom, EINA_LOG_LEVEL_ERR,
59                   file, func_name, line,
60                   "Eo ID %p is not a valid %s. "
61                   "Current thread: %s. "
62                   "%s or this was never a valid %s ID. "
63                   "(domain=%i, current_domain=%i, local_domain=%i, "
64                   "available_domains=[%s %s %s %s], "
65                   "generation=%lx, id=%lx, ref=%i)",
66                   (void *)obj_id,
67                   type,
68                   tself,
69                   reason,
70                   type,
71                   (int)domain,
72                   (int)data->domain_stack[data->stack_top],
73                   (int)data->local_domain,
74                   (data->tables[0]) ? "0" : " ",
75                   (data->tables[1]) ? "1" : " ",
76                   (data->tables[2]) ? "2" : " ",
77                   (data->tables[3]) ? "3" : " ",
78                   (unsigned long)(obj_id & MASK_GENERATIONS),
79                   (unsigned long)(obj_id >> SHIFT_ENTRY_ID) & (MAX_ENTRY_ID | MAX_TABLE_ID | MAX_MID_TABLE_ID),
80                   (int)(obj_id >> REF_TAG_SHIFT) & 0x1);
81    _eo_log_obj_report(obj_id, EINA_LOG_LEVEL_ERR, func_name, file, line);
82 }
83
84 _Eo_Object *
85 _eo_obj_pointer_get(const Eo_Id obj_id, const char *func_name, const char *file, int line)
86 {
87    _Eo_Id_Entry *entry;
88    Generation_Counter generation;
89    Table_Index mid_table_id, table_id, entry_id;
90    Eo_Id tag_bit;
91    Eo_Id_Data *data;
92    Eo_Id_Table_Data *tdata;
93    unsigned char domain;
94
95    // NULL objects will just be sensibly ignored. not worth complaining
96    // every single time.
97
98    data = _eo_table_data_get();
99    EINA_PREFETCH(&(data->tables[0]));
100    domain = (obj_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
101    tdata = _eo_table_data_table_get(data, domain);
102    EINA_PREFETCH(&(tdata->cache.id));
103    if (EINA_UNLIKELY(!tdata)) goto err;
104
105
106    if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED))
107      {
108         if (obj_id == tdata->cache.id)
109           return tdata->cache.object;
110
111         mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID;
112         EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id]));
113         table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID;
114         entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
115         generation = obj_id & MASK_GENERATIONS;
116
117         // get tag bit to check later down below - pipelining
118         tag_bit = (obj_id) & MASK_OBJ_TAG;
119         if (!obj_id) goto err_null;
120         else if (!tag_bit) goto err;
121
122         // Check the validity of the entry
123         if (tdata->eo_ids_tables[mid_table_id])
124           {
125              _Eo_Ids_Table *tab = TABLE_FROM_IDS;
126
127              if (tab)
128                {
129                   entry = &(tab->entries[entry_id]);
130                   if (entry->active && (entry->generation == generation))
131                     {
132                        // Cache the result of that lookup
133                        tdata->cache.object = entry->ptr;
134                        tdata->cache.id = obj_id;
135                        return entry->ptr;
136                     }
137                }
138           }
139         goto err;
140      }
141    else
142      {
143         eina_lock_take(&(_eo_table_data_shared_data->obj_lock));
144         if (obj_id == tdata->cache.id)
145         // yes we return keeping the lock locked. thats why
146         // you must call _eo_obj_pointer_done() wrapped
147         // by EO_OBJ_DONE() to release
148           return tdata->cache.object;
149
150         mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID;
151         EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id]));
152         table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID;
153         entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
154         generation = obj_id & MASK_GENERATIONS;
155
156         // get tag bit to check later down below - pipelining
157         tag_bit = (obj_id) & MASK_OBJ_TAG;
158         if (!obj_id) goto err_shared_null;
159         else if (!tag_bit) goto err_shared;
160
161         // Check the validity of the entry
162         if (tdata->eo_ids_tables[mid_table_id])
163           {
164              _Eo_Ids_Table *tab = TABLE_FROM_IDS;
165
166              if (tab)
167                {
168                   entry = &(tab->entries[entry_id]);
169                   if (entry->active && (entry->generation == generation))
170                     {
171                        // Cache the result of that lookup
172                        tdata->cache.object = entry->ptr;
173                        tdata->cache.id = obj_id;
174                        // yes we return keeping the lock locked. thats why
175                        // you must call _eo_obj_pointer_done() wrapped
176                        // by EO_OBJ_DONE() to release
177                        return entry->ptr;
178                     }
179                }
180           }
181         goto err_shared;
182      }
183 err_shared_null:
184    eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
185 err_null:
186    eina_log_print(_eo_log_dom,
187                   EINA_LOG_LEVEL_DBG,
188                   file, func_name, line,
189                   "obj_id is NULL. Possibly unintended access?");
190    return NULL;
191 err_shared:
192    eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
193 err:
194    _eo_obj_pointer_invalid(obj_id, data, domain, func_name, file, line);
195    return NULL;
196 }