1 /*
2  * Copyright (c) 2016, NVIDIA CORPORATION.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and/or associated documentation files (the
6  * "Materials"), to deal in the Materials without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Materials, and to
9  * permit persons to whom the Materials are furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * unaltered in all copies or substantial portions of the Materials.
14  * Any additions, deletions, or changes to the original source files
15  * must be clearly indicated in accompanying documentation.
16  *
17  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
24  */
25 
26 #include "winsys_dispatch.h"
27 
28 #include "glvnd_pthread.h"
29 #include "lkdhash.h"
30 #include <assert.h>
31 
32 // The initial size to use when we allocate the function list. This is large
33 // enough to hold all of the functions defined in libGLX.
34 #define INITIAL_LIST_SIZE 64
35 
36 typedef struct __GLVNDwinsysDispatchIndexEntryRec {
37     char *name;
38     void *dispatchFunc;
39 } __GLVNDwinsysDispatchIndexEntry;
40 
41 static __GLVNDwinsysDispatchIndexEntry *dispatchIndexList = NULL;
42 static int dispatchIndexCount = 0;
43 static int dispatchIndexAllocCount = 0;
44 
__glvndWinsysDispatchInit(void)45 void __glvndWinsysDispatchInit(void)
46 {
47     // Nothing to do.
48 }
49 
__glvndWinsysDispatchCleanup(void)50 void __glvndWinsysDispatchCleanup(void)
51 {
52     int i;
53 
54     for (i=0; i<dispatchIndexCount; i++) {
55         free(dispatchIndexList[i].name);
56     }
57     free(dispatchIndexList);
58     dispatchIndexList = NULL;
59     dispatchIndexCount = dispatchIndexAllocCount = 0;
60 }
61 
62 
__glvndWinsysDispatchFindIndex(const char * name)63 int __glvndWinsysDispatchFindIndex(const char *name)
64 {
65     int i;
66 
67     for (i=0; i<dispatchIndexCount; i++) {
68         if (strcmp(dispatchIndexList[i].name, name) == 0) {
69             return i;
70         }
71     }
72 
73     return -1;
74 }
75 
__glvndWinsysDispatchAllocIndex(const char * name,void * dispatch)76 int __glvndWinsysDispatchAllocIndex(const char *name, void *dispatch)
77 {
78     assert(__glvndWinsysDispatchFindIndex(name) < 0);
79 
80     if (dispatchIndexCount == dispatchIndexAllocCount) {
81         __GLVNDwinsysDispatchIndexEntry *newList;
82         int newSize = dispatchIndexAllocCount * 2;
83         if (newSize <= 0) {
84             newSize = INITIAL_LIST_SIZE;
85         }
86 
87         newList = realloc(dispatchIndexList, newSize * sizeof(__GLVNDwinsysDispatchIndexEntry));
88         if (newList == NULL) {
89             return -1;
90         }
91 
92         dispatchIndexList = newList;
93         dispatchIndexAllocCount = newSize;
94     }
95 
96     dispatchIndexList[dispatchIndexCount].name = strdup(name);
97     if (dispatchIndexList[dispatchIndexCount].name == NULL) {
98         return -1;
99     }
100 
101     dispatchIndexList[dispatchIndexCount].dispatchFunc = dispatch;
102     return dispatchIndexCount++;
103 }
104 
__glvndWinsysDispatchGetName(int index)105 const char *__glvndWinsysDispatchGetName(int index)
106 {
107     if (index >= 0 && index < dispatchIndexCount) {
108         return dispatchIndexList[index].name;
109     } else {
110         return NULL;
111     }
112 }
113 
__glvndWinsysDispatchGetDispatch(int index)114 void *__glvndWinsysDispatchGetDispatch(int index)
115 {
116     if (index >= 0 && index < dispatchIndexCount) {
117         return dispatchIndexList[index].dispatchFunc;
118     } else {
119         return NULL;
120     }
121 }
122 
__glvndWinsysDispatchGetCount(void)123 int __glvndWinsysDispatchGetCount(void)
124 {
125     return dispatchIndexCount;
126 }
127 
128 
129 typedef struct __GLVNDwinsysDispatchFuncHashRec {
130     int index;
131     void *implFunc;
132     UT_hash_handle hh;
133 } __GLVNDwinsysDispatchFuncHash;
134 
135 struct __GLVNDwinsysVendorDispatchRec {
136     DEFINE_LKDHASH(__GLVNDwinsysDispatchFuncHash, table);
137 };
138 
__glvndWinsysVendorDispatchCreate(void)139 __GLVNDwinsysVendorDispatch *__glvndWinsysVendorDispatchCreate(void)
140 {
141     __GLVNDwinsysVendorDispatch *table = (__GLVNDwinsysVendorDispatch *)
142         malloc(sizeof(__GLVNDwinsysVendorDispatch));
143     if (table == NULL) {
144         return NULL;
145     }
146 
147     LKDHASH_INIT(table->table);
148     return table;
149 }
150 
__glvndWinsysVendorDispatchDestroy(__GLVNDwinsysVendorDispatch * table)151 void __glvndWinsysVendorDispatchDestroy(__GLVNDwinsysVendorDispatch *table)
152 {
153     if (table != NULL) {
154         LKDHASH_TEARDOWN(__GLVNDwinsysDispatchFuncHash,
155                          table->table, NULL, NULL, 0);
156         free(table);
157     }
158 }
159 
__glvndWinsysVendorDispatchAddFunc(__GLVNDwinsysVendorDispatch * table,int index,void * func)160 int __glvndWinsysVendorDispatchAddFunc(__GLVNDwinsysVendorDispatch *table, int index, void *func)
161 {
162     __GLVNDwinsysDispatchFuncHash *entry;
163 
164     LKDHASH_WRLOCK(table->table);
165     HASH_FIND_INT(_LH(table->table), &index, entry);
166     if (entry == NULL) {
167         entry = (__GLVNDwinsysDispatchFuncHash *) malloc(sizeof(__GLVNDwinsysDispatchFuncHash));
168         if (entry == NULL) {
169             LKDHASH_UNLOCK(table->table);
170             return -1;
171         }
172 
173         entry->index = index;
174         HASH_ADD_INT(_LH(table->table), index, entry);
175     }
176     entry->implFunc = func;
177     LKDHASH_UNLOCK(table->table);
178     return 0;
179 }
180 
__glvndWinsysVendorDispatchLookupFunc(__GLVNDwinsysVendorDispatch * table,int index)181 void *__glvndWinsysVendorDispatchLookupFunc(__GLVNDwinsysVendorDispatch *table, int index)
182 {
183     __GLVNDwinsysDispatchFuncHash *entry;
184     void *func;
185 
186     LKDHASH_RDLOCK(table->table);
187     HASH_FIND_INT(_LH(table->table), &index, entry);
188     if (entry != NULL) {
189         func = entry->implFunc;
190     } else {
191         func = NULL;
192     }
193     LKDHASH_UNLOCK(table->table);
194 
195     return func;
196 }
197 
198