5 #include "eo_ptr_indirection.h"
7 extern Eina_Thread _efl_object_main_thread;
9 //////////////////////////////////////////////////////////////////////////
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;
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;
20 //////////////////////////////////////////////////////////////////////////
23 _eo_pointer_error(const Eo *obj_id, const char *func_name, const char *file, int line, const char *fmt, ...)
25 /* NOTE: this function exists to allow easy breakpoint on pointer errors */
28 eina_log_vprint(_eo_log_dom, EINA_LOG_LEVEL_ERR, file, func_name, line, fmt, args);
30 _eo_log_obj_report((Eo_Id)obj_id, EINA_LOG_LEVEL_ERR, func_name, file, line);
34 _eo_obj_pointer_invalid(const Eo_Id obj_id,
37 const char *func_name,
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";
46 if (obj_id & MASK_CLASS_TAG) type = "class";
47 if (thread != _efl_object_main_thread)
49 snprintf(tbuf, sizeof(tbuf), "%p", (void *)thread);
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";
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)",
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);
85 _eo_obj_pointer_get(const Eo_Id obj_id, const char *func_name, const char *file, int line)
88 Generation_Counter generation;
89 Table_Index mid_table_id, table_id, entry_id;
92 Eo_Id_Table_Data *tdata;
95 // NULL objects will just be sensibly ignored. not worth complaining
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;
106 if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED))
108 if (obj_id == tdata->cache.id)
109 return tdata->cache.object;
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;
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;
122 // Check the validity of the entry
123 if (tdata->eo_ids_tables[mid_table_id])
125 _Eo_Ids_Table *tab = TABLE_FROM_IDS;
129 entry = &(tab->entries[entry_id]);
130 if (entry->active && (entry->generation == generation))
132 // Cache the result of that lookup
133 tdata->cache.object = entry->ptr;
134 tdata->cache.id = obj_id;
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;
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;
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;
161 // Check the validity of the entry
162 if (tdata->eo_ids_tables[mid_table_id])
164 _Eo_Ids_Table *tab = TABLE_FROM_IDS;
168 entry = &(tab->entries[entry_id]);
169 if (entry->active && (entry->generation == generation))
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
184 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
186 eina_log_print(_eo_log_dom,
188 file, func_name, line,
189 "obj_id is NULL. Possibly unintended access?");
192 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
194 _eo_obj_pointer_invalid(obj_id, data, domain, func_name, file, line);