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