1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 2010 LunarG Inc.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci * Authors:
25bf215546Sopenharmony_ci *    Chia-I Wu <olv@lunarg.com>
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <stdlib.h>
29bf215546Sopenharmony_ci#include <string.h>
30bf215546Sopenharmony_ci#include <assert.h>
31bf215546Sopenharmony_ci#include "c11/threads.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "util/macros.h"
34bf215546Sopenharmony_ci#include "u_current.h"
35bf215546Sopenharmony_ci#include "entry.h"
36bf215546Sopenharmony_ci#include "stub.h"
37bf215546Sopenharmony_ci#include "table.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_cistruct mapi_stub {
41bf215546Sopenharmony_ci   const void *name;
42bf215546Sopenharmony_ci   int slot;
43bf215546Sopenharmony_ci   mapi_func addr;
44bf215546Sopenharmony_ci};
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci/* define public_string_pool and public_stubs */
47bf215546Sopenharmony_ci#define MAPI_TMP_PUBLIC_STUBS
48bf215546Sopenharmony_ci#include "mapi_tmp.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_cistatic struct mapi_stub dynamic_stubs[MAPI_TABLE_NUM_DYNAMIC];
51bf215546Sopenharmony_cistatic int num_dynamic_stubs;
52bf215546Sopenharmony_cistatic int next_dynamic_slot = MAPI_TABLE_NUM_STATIC;
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_civoid
55bf215546Sopenharmony_cistub_init_once(void)
56bf215546Sopenharmony_ci{
57bf215546Sopenharmony_ci   static once_flag flag = ONCE_FLAG_INIT;
58bf215546Sopenharmony_ci   call_once(&flag, entry_patch_public);
59bf215546Sopenharmony_ci}
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_cistatic int
62bf215546Sopenharmony_cistub_compare(const void *key, const void *elem)
63bf215546Sopenharmony_ci{
64bf215546Sopenharmony_ci   const char *name = (const char *) key;
65bf215546Sopenharmony_ci   const struct mapi_stub *stub = (const struct mapi_stub *) elem;
66bf215546Sopenharmony_ci   const char *stub_name;
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   stub_name = &public_string_pool[(size_t) stub->name];
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   return strcmp(name, stub_name);
71bf215546Sopenharmony_ci}
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci/**
74bf215546Sopenharmony_ci * Return the public stub with the given name.
75bf215546Sopenharmony_ci */
76bf215546Sopenharmony_ciconst struct mapi_stub *
77bf215546Sopenharmony_cistub_find_public(const char *name)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   return (const struct mapi_stub *) bsearch(name, public_stubs,
80bf215546Sopenharmony_ci         ARRAY_SIZE(public_stubs), sizeof(public_stubs[0]), stub_compare);
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci/**
84bf215546Sopenharmony_ci * Add a dynamic stub.
85bf215546Sopenharmony_ci */
86bf215546Sopenharmony_cistatic struct mapi_stub *
87bf215546Sopenharmony_cistub_add_dynamic(const char *name)
88bf215546Sopenharmony_ci{
89bf215546Sopenharmony_ci   struct mapi_stub *stub;
90bf215546Sopenharmony_ci   int idx;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   idx = num_dynamic_stubs;
93bf215546Sopenharmony_ci   /* minus 1 to make sure we can never reach the last slot */
94bf215546Sopenharmony_ci   if (idx >= MAPI_TABLE_NUM_DYNAMIC - 1)
95bf215546Sopenharmony_ci      return NULL;
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   stub = &dynamic_stubs[idx];
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   /* dispatch to the last slot, which is reserved for no-op */
100bf215546Sopenharmony_ci   stub->addr = entry_generate(
101bf215546Sopenharmony_ci         MAPI_TABLE_NUM_STATIC + MAPI_TABLE_NUM_DYNAMIC - 1);
102bf215546Sopenharmony_ci   if (!stub->addr)
103bf215546Sopenharmony_ci      return NULL;
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci   stub->name = (const void *) strdup(name);
106bf215546Sopenharmony_ci   /* to be fixed later */
107bf215546Sopenharmony_ci   stub->slot = -1;
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   num_dynamic_stubs = idx + 1;
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci   return stub;
112bf215546Sopenharmony_ci}
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci/**
115bf215546Sopenharmony_ci * Return the dynamic stub with the given name.  If no such stub exists and
116bf215546Sopenharmony_ci * generate is true, a new stub is generated.
117bf215546Sopenharmony_ci */
118bf215546Sopenharmony_cistruct mapi_stub *
119bf215546Sopenharmony_cistub_find_dynamic(const char *name, int generate)
120bf215546Sopenharmony_ci{
121bf215546Sopenharmony_ci   static mtx_t dynamic_mutex = _MTX_INITIALIZER_NP;
122bf215546Sopenharmony_ci   struct mapi_stub *stub = NULL;
123bf215546Sopenharmony_ci   int count, i;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   mtx_lock(&dynamic_mutex);
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   if (generate)
128bf215546Sopenharmony_ci      assert(!stub_find_public(name));
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   count = num_dynamic_stubs;
131bf215546Sopenharmony_ci   for (i = 0; i < count; i++) {
132bf215546Sopenharmony_ci      if (strcmp(name, (const char *) dynamic_stubs[i].name) == 0) {
133bf215546Sopenharmony_ci         stub = &dynamic_stubs[i];
134bf215546Sopenharmony_ci         break;
135bf215546Sopenharmony_ci      }
136bf215546Sopenharmony_ci   }
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   /* generate a dynamic stub */
139bf215546Sopenharmony_ci   if (generate && !stub)
140bf215546Sopenharmony_ci         stub = stub_add_dynamic(name);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   mtx_unlock(&dynamic_mutex);
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   return stub;
145bf215546Sopenharmony_ci}
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_cistatic const struct mapi_stub *
148bf215546Sopenharmony_cisearch_table_by_slot(const struct mapi_stub *table, size_t num_entries,
149bf215546Sopenharmony_ci                     int slot)
150bf215546Sopenharmony_ci{
151bf215546Sopenharmony_ci   size_t i;
152bf215546Sopenharmony_ci   for (i = 0; i < num_entries; ++i) {
153bf215546Sopenharmony_ci      if (table[i].slot == slot)
154bf215546Sopenharmony_ci         return &table[i];
155bf215546Sopenharmony_ci   }
156bf215546Sopenharmony_ci   return NULL;
157bf215546Sopenharmony_ci}
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ciconst struct mapi_stub *
160bf215546Sopenharmony_cistub_find_by_slot(int slot)
161bf215546Sopenharmony_ci{
162bf215546Sopenharmony_ci   const struct mapi_stub *stub =
163bf215546Sopenharmony_ci      search_table_by_slot(public_stubs, ARRAY_SIZE(public_stubs), slot);
164bf215546Sopenharmony_ci   if (stub)
165bf215546Sopenharmony_ci      return stub;
166bf215546Sopenharmony_ci   return search_table_by_slot(dynamic_stubs, num_dynamic_stubs, slot);
167bf215546Sopenharmony_ci}
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_civoid
170bf215546Sopenharmony_cistub_fix_dynamic(struct mapi_stub *stub, const struct mapi_stub *alias)
171bf215546Sopenharmony_ci{
172bf215546Sopenharmony_ci   int slot;
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   if (stub->slot >= 0)
175bf215546Sopenharmony_ci      return;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   if (alias)
178bf215546Sopenharmony_ci      slot = alias->slot;
179bf215546Sopenharmony_ci   else
180bf215546Sopenharmony_ci      slot = next_dynamic_slot++;
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   entry_patch(stub->addr, slot);
183bf215546Sopenharmony_ci   stub->slot = slot;
184bf215546Sopenharmony_ci}
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci/**
187bf215546Sopenharmony_ci * Return the name of a stub.
188bf215546Sopenharmony_ci */
189bf215546Sopenharmony_ciconst char *
190bf215546Sopenharmony_cistub_get_name(const struct mapi_stub *stub)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci   const char *name;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   if (stub >= public_stubs &&
195bf215546Sopenharmony_ci       stub < public_stubs + ARRAY_SIZE(public_stubs))
196bf215546Sopenharmony_ci      name = &public_string_pool[(size_t) stub->name];
197bf215546Sopenharmony_ci   else
198bf215546Sopenharmony_ci      name = (const char *) stub->name;
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   return name;
201bf215546Sopenharmony_ci}
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci/**
204bf215546Sopenharmony_ci * Return the slot of a stub.
205bf215546Sopenharmony_ci */
206bf215546Sopenharmony_ciint
207bf215546Sopenharmony_cistub_get_slot(const struct mapi_stub *stub)
208bf215546Sopenharmony_ci{
209bf215546Sopenharmony_ci   return stub->slot;
210bf215546Sopenharmony_ci}
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci/**
213bf215546Sopenharmony_ci * Return the address of a stub.
214bf215546Sopenharmony_ci */
215bf215546Sopenharmony_cimapi_func
216bf215546Sopenharmony_cistub_get_addr(const struct mapi_stub *stub)
217bf215546Sopenharmony_ci{
218bf215546Sopenharmony_ci   assert(stub->addr || (unsigned int) stub->slot < MAPI_TABLE_NUM_STATIC);
219bf215546Sopenharmony_ci   return (stub->addr) ? stub->addr : entry_get_public(stub->slot);
220bf215546Sopenharmony_ci}
221