mapi: Add a generic C dispatcher.
[mesa.git] / src / mapi / mapi / stub.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include <stdlib.h>
30 #include <stddef.h> /* for offsetof */
31 #include <string.h>
32 #include <assert.h>
33
34 #include "u_current.h"
35 #include "u_thread.h"
36 #include "entry.h"
37 #include "stub.h"
38 #include "table.h"
39
40 #define MAPI_TABLE_FIRST_DYNAMIC \
41 (offsetof(struct mapi_table, dynamic0) / sizeof(mapi_func))
42 #define MAPI_TABLE_NUM_DYNAMIC \
43 ((offsetof(struct mapi_table, last) - \
44 offsetof(struct mapi_table, dynamic0)) / sizeof(mapi_func))
45 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
46
47 /*
48 * This will define public_string_pool, public_sorted_indices, and
49 * public_stubs.
50 */
51 #define MAPI_TMP_PUBLIC_STUBS
52 #include "mapi_tmp.h"
53
54 static struct mapi_stub dynamic_stubs[MAPI_TABLE_NUM_DYNAMIC];
55 static int num_dynamic_stubs;
56 static int next_dynamic_slot = MAPI_TABLE_FIRST_DYNAMIC;
57
58 void
59 stub_init_once(void)
60 {
61 #ifdef PTHREADS
62 static pthread_once_t once = PTHREAD_ONCE_INIT;
63 pthread_once(&once, entry_patch_public);
64 #else
65 static int first = 1;
66 if (first) {
67 first = 0;
68 entry_patch_public();
69 }
70 #endif
71 }
72
73 static int
74 stub_compare(const void *key, const void *elem)
75 {
76 const char *name = (const char *) key;
77 const int *index = (const int *) elem;
78 const struct mapi_stub *stub;
79 const char *stub_name;
80
81 stub = &public_stubs[*index];
82 stub_name = &public_string_pool[(unsigned long) stub->name];
83
84 return strcmp(name, stub_name);
85 }
86
87 /**
88 * Return the public stub with the given name.
89 */
90 const struct mapi_stub *
91 stub_find_public(const char *name)
92 {
93 const int *index;
94
95 index = (const int *) bsearch(name, public_sorted_indices,
96 ARRAY_SIZE(public_sorted_indices) - 1,
97 sizeof(public_sorted_indices[0]), stub_compare);
98
99 return (index) ? &public_stubs[*index] : NULL;
100 }
101
102 /**
103 * Add a dynamic stub.
104 */
105 static struct mapi_stub *
106 stub_add_dynamic(const char *name)
107 {
108 struct mapi_stub *stub;
109 int idx;
110
111 idx = num_dynamic_stubs;
112 if (idx >= MAPI_TABLE_NUM_DYNAMIC)
113 return NULL;
114
115 stub = &dynamic_stubs[idx];
116
117 /* dispatch to mapi_table->last, which is always no-op */
118 stub->addr =
119 entry_generate(MAPI_TABLE_FIRST_DYNAMIC + MAPI_TABLE_NUM_DYNAMIC);
120 if (!stub->addr)
121 return NULL;
122
123 stub->name = (const void *) name;
124 /* to be fixed later */
125 stub->slot = -1;
126
127 num_dynamic_stubs = idx + 1;
128
129 return stub;
130 }
131
132 /**
133 * Return the dynamic stub with the given name. If no such stub exists and
134 * generate is true, a new stub is generated.
135 */
136 struct mapi_stub *
137 stub_find_dynamic(const char *name, int generate)
138 {
139 u_mutex_declare_static(dynamic_mutex);
140 struct mapi_stub *stub = NULL;
141 int count, i;
142
143 u_mutex_lock(dynamic_mutex);
144
145 if (generate)
146 assert(!stub_find_public(name));
147
148 count = num_dynamic_stubs;
149 for (i = 0; i < count; i++) {
150 if (strcmp(name, (const char *) dynamic_stubs[i].name) == 0) {
151 stub = &dynamic_stubs[i];
152 break;
153 }
154 }
155
156 /* generate a dynamic stub */
157 if (generate && !stub)
158 stub = stub_add_dynamic(name);
159
160 u_mutex_unlock(dynamic_mutex);
161
162 return stub;
163 }
164
165 void
166 stub_fix_dynamic(struct mapi_stub *stub, const struct mapi_stub *alias)
167 {
168 int slot;
169
170 if (stub->slot >= 0)
171 return;
172
173 if (alias)
174 slot = alias->slot;
175 else
176 slot = next_dynamic_slot++;
177
178 entry_patch(stub->addr, slot);
179 stub->slot = slot;
180 }