1/*
2    Copyright (c) 2014 Intel Corporation.  All Rights Reserved.
3
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions
6    are met:
7
8      * Redistributions of source code must retain the above copyright
9        notice, this list of conditions and the following disclaimer.
10      * Redistributions in binary form must reproduce the above copyright
11        notice, this list of conditions and the following disclaimer in the
12        documentation and/or other materials provided with the distribution.
13      * Neither the name of Intel Corporation nor the names of its
14        contributors may be used to endorse or promote products derived
15        from this software without specific prior written permission.
16
17    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30
31#include "offload_table.h"
32#include "offload_common.h"
33
34#if !HOST_LIBRARY
35// Predefined offload entries
36extern void omp_set_num_threads_lrb(void*);
37extern void omp_get_max_threads_lrb(void*);
38extern void omp_get_num_procs_lrb(void*);
39extern void omp_set_dynamic_lrb(void*);
40extern void omp_get_dynamic_lrb(void*);
41extern void omp_set_nested_lrb(void*);
42extern void omp_get_nested_lrb(void*);
43extern void omp_set_schedule_lrb(void*);
44extern void omp_get_schedule_lrb(void*);
45
46extern void omp_init_lock_lrb(void*);
47extern void omp_destroy_lock_lrb(void*);
48extern void omp_set_lock_lrb(void*);
49extern void omp_unset_lock_lrb(void*);
50extern void omp_test_lock_lrb(void*);
51
52extern void omp_init_nest_lock_lrb(void*);
53extern void omp_destroy_nest_lock_lrb(void*);
54extern void omp_set_nest_lock_lrb(void*);
55extern void omp_unset_nest_lock_lrb(void*);
56extern void omp_test_nest_lock_lrb(void*);
57
58// Predefined entries on the target side
59static FuncTable::Entry predefined_entries[] = {
60    "omp_set_num_threads_target",
61    (void*) &omp_set_num_threads_lrb,
62    "omp_get_max_threads_target",
63    (void*) &omp_get_max_threads_lrb,
64    "omp_get_num_procs_target",
65    (void*) &omp_get_num_procs_lrb,
66    "omp_set_dynamic_target",
67    (void*) &omp_set_dynamic_lrb,
68    "omp_get_dynamic_target",
69    (void*) &omp_get_dynamic_lrb,
70    "omp_set_nested_target",
71    (void*) &omp_set_nested_lrb,
72    "omp_get_nested_target",
73    (void*) &omp_get_nested_lrb,
74    "omp_set_schedule_target",
75    (void*) &omp_set_schedule_lrb,
76    "omp_get_schedule_target",
77    (void*) &omp_get_schedule_lrb,
78
79    "omp_init_lock_target",
80    (void*) &omp_init_lock_lrb,
81    "omp_destroy_lock_target",
82    (void*) &omp_destroy_lock_lrb,
83    "omp_set_lock_target",
84    (void*) &omp_set_lock_lrb,
85    "omp_unset_lock_target",
86    (void*) &omp_unset_lock_lrb,
87    "omp_test_lock_target",
88    (void*) &omp_test_lock_lrb,
89
90    "omp_init_nest_lock_target",
91    (void*) &omp_init_nest_lock_lrb,
92    "omp_destroy_nest_lock_target",
93    (void*) &omp_destroy_nest_lock_lrb,
94    "omp_set_nest_lock_target",
95    (void*) &omp_set_nest_lock_lrb,
96    "omp_unset_nest_lock_target",
97    (void*) &omp_unset_nest_lock_lrb,
98    "omp_test_nest_lock_target",
99    (void*) &omp_test_nest_lock_lrb,
100
101    (const char*) -1,
102    (void*) -1
103};
104
105static FuncList::Node predefined_table = {
106    { predefined_entries, -1 },
107    0, 0
108};
109
110// Entry table
111FuncList __offload_entries(&predefined_table);
112#else
113FuncList __offload_entries;
114#endif // !HOST_LIBRARY
115
116// Function table. No predefined entries.
117FuncList __offload_funcs;
118
119// Var table
120VarList  __offload_vars;
121
122// Given the function name returns the associtated function pointer
123const void* FuncList::find_addr(const char *name)
124{
125    const void* func = 0;
126
127    m_lock.lock();
128
129    for (Node *n = m_head; n != 0; n = n->next) {
130        for (const Table::Entry *e = n->table.entries;
131             e->name != (const char*) -1; e++) {
132            if (e->name != 0 && strcmp(e->name, name) == 0) {
133                func = e->func;
134                break;
135            }
136        }
137    }
138
139    m_lock.unlock();
140
141    return func;
142}
143
144// Given the function pointer returns the associtated function name
145const char* FuncList::find_name(const void *func)
146{
147    const char* name = 0;
148
149    m_lock.lock();
150
151    for (Node *n = m_head; n != 0; n = n->next) {
152        for (const Table::Entry *e = n->table.entries;
153             e->name != (const char*) -1; e++) {
154            if (e->func == func) {
155                name = e->name;
156                break;
157            }
158        }
159    }
160
161    m_lock.unlock();
162
163    return name;
164}
165
166// Returns max name length from all tables
167int64_t FuncList::max_name_length(void)
168{
169    if (m_max_name_len < 0) {
170        m_lock.lock();
171
172        m_max_name_len = 0;
173        for (Node *n = m_head; n != 0; n = n->next) {
174            if (n->table.max_name_len < 0) {
175                n->table.max_name_len = 0;
176
177                // calculate max name length in a single table
178                for (const Table::Entry *e = n->table.entries;
179                     e->name != (const char*) -1; e++) {
180                    if (e->name != 0) {
181                        size_t len = strlen(e->name) + 1;
182                        if (n->table.max_name_len < len) {
183                            n->table.max_name_len = len;
184                        }
185                    }
186                }
187            }
188
189            // select max from all tables
190            if (m_max_name_len < n->table.max_name_len) {
191                m_max_name_len = n->table.max_name_len;
192            }
193        }
194
195        m_lock.unlock();
196    }
197    return m_max_name_len;
198}
199
200// Debugging dump
201void FuncList::dump(void)
202{
203    OFFLOAD_DEBUG_TRACE(2, "Function table:\n");
204
205    m_lock.lock();
206
207    for (Node *n = m_head; n != 0; n = n->next) {
208        for (const Table::Entry *e = n->table.entries;
209             e->name != (const char*) -1; e++) {
210            if (e->name != 0) {
211                OFFLOAD_DEBUG_TRACE(2, "%p %s\n", e->func, e->name);
212            }
213        }
214    }
215
216    m_lock.unlock();
217}
218
219// Debugging dump
220void VarList::dump(void)
221{
222    OFFLOAD_DEBUG_TRACE(2, "Var table:\n");
223
224    m_lock.lock();
225
226    for (Node *n = m_head; n != 0; n = n->next) {
227        for (const Table::Entry *e = n->table.entries;
228             e->name != (const char*) -1; e++) {
229            if (e->name != 0) {
230#if HOST_LIBRARY
231                OFFLOAD_DEBUG_TRACE(2, "%s %p %ld\n", e->name, e->addr,
232                                    e->size);
233#else  // HOST_LIBRARY
234                OFFLOAD_DEBUG_TRACE(2, "%s %p\n", e->name, e->addr);
235#endif // HOST_LIBRARY
236            }
237        }
238    }
239
240    m_lock.unlock();
241}
242
243//
244int64_t VarList::table_size(int64_t &nelems)
245{
246    int64_t length = 0;
247
248    nelems = 0;
249
250    // calculate string table size and number of elements
251    for (Node *n = m_head; n != 0; n = n->next) {
252        for (const Table::Entry *e = n->table.entries;
253             e->name != (const char*) -1; e++) {
254            if (e->name != 0) {
255                length += strlen(e->name) + 1;
256                nelems++;
257            }
258        }
259    }
260
261    return nelems * sizeof(BufEntry) + length;
262}
263
264// copy table to the gven buffer
265void VarList::table_copy(void *buf, int64_t nelems)
266{
267    BufEntry* elems = static_cast<BufEntry*>(buf);
268    char*     names = reinterpret_cast<char*>(elems + nelems);
269
270    // copy entries to buffer
271    for (Node *n = m_head; n != 0; n = n->next) {
272        for (const Table::Entry *e = n->table.entries;
273             e->name != (const char*) -1; e++) {
274            if (e->name != 0) {
275                // name field contains offset to the name from the beginning
276                // of the buffer
277                elems->name = names - static_cast<char*>(buf);
278                elems->addr = reinterpret_cast<intptr_t>(e->addr);
279
280                // copy name to string table
281                const char *name = e->name;
282                while ((*names++ = *name++) != '\0');
283
284                elems++;
285            }
286        }
287    }
288}
289
290// patch name offsets in a buffer
291void VarList::table_patch_names(void *buf, int64_t nelems)
292{
293    BufEntry* elems = static_cast<BufEntry*>(buf);
294    for (int i = 0; i < nelems; i++) {
295        elems[i].name += reinterpret_cast<intptr_t>(buf);
296    }
297}
298
299// Adds given list element to the global lookup table list
300extern "C" void __offload_register_tables(
301    FuncList::Node *entry_table,
302    FuncList::Node *func_table,
303    VarList::Node *var_table
304)
305{
306    OFFLOAD_DEBUG_TRACE(2, "Registering offload function entry table %p\n",
307                           entry_table);
308    __offload_entries.add_table(entry_table);
309
310    OFFLOAD_DEBUG_TRACE(2, "Registering function table %p\n", func_table);
311    __offload_funcs.add_table(func_table);
312
313    OFFLOAD_DEBUG_TRACE(2, "Registering var table %p\n", var_table);
314    __offload_vars.add_table(var_table);
315}
316
317// Removes given list element from the global lookup table list
318extern "C" void __offload_unregister_tables(
319    FuncList::Node *entry_table,
320    FuncList::Node *func_table,
321    VarList::Node *var_table
322)
323{
324    __offload_entries.remove_table(entry_table);
325
326    OFFLOAD_DEBUG_TRACE(2, "Unregistering function table %p\n", func_table);
327    __offload_funcs.remove_table(func_table);
328
329    OFFLOAD_DEBUG_TRACE(2, "Unregistering var table %p\n", var_table);
330    __offload_vars.remove_table(var_table);
331}
332