1 /*
2  * Copyright (c) 2013, 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 <pthread.h>
27 #include <string.h>
28 
29 #if defined(HASH_DEBUG)
30 # include <stdio.h>
31 #endif
32 
33 #include "libeglcurrent.h"
34 #include "libeglmapping.h"
35 #include "glvnd_pthread.h"
36 #include "egldispatchstubs.h"
37 #include "utils_misc.h"
38 #include "trace.h"
39 
40 #include "lkdhash.h"
41 
42 static glvnd_mutex_t dispatchIndexMutex = GLVND_MUTEX_INITIALIZER;
43 
44 typedef struct __EGLdeviceInfoRec {
45     EGLDeviceEXT handle;
46     __EGLvendorInfo *vendor;
47     UT_hash_handle hh;
48 } __EGLdeviceInfo;
49 static DEFINE_INITIALIZED_LKDHASH(__EGLdeviceInfo, __eglDeviceHash);
50 
51 /****************************************************************************/
52 
53 typedef struct __EGLdisplayInfoHashRec {
54     __EGLdisplayInfo info;
55     UT_hash_handle hh;
56 } __EGLdisplayInfoHash;
57 
58 static DEFINE_INITIALIZED_LKDHASH(__EGLdisplayInfoHash, __eglDisplayInfoHash);
59 
__eglGetEGLDispatchAddress(const char * procName)60 __eglMustCastToProperFunctionPointerType __eglGetEGLDispatchAddress(const char *procName)
61 {
62     struct glvnd_list *vendorList = __eglLoadVendors();
63     __EGLvendorInfo *vendor;
64     __eglMustCastToProperFunctionPointerType addr = NULL;
65     int index;
66 
67     __glvndPthreadFuncs.mutex_lock(&dispatchIndexMutex);
68 
69     index = __glvndWinsysDispatchFindIndex(procName);
70     if (index >= 0) {
71         addr = (__eglMustCastToProperFunctionPointerType) __glvndWinsysDispatchGetDispatch(index);
72         __glvndPthreadFuncs.mutex_unlock(&dispatchIndexMutex);
73         return addr;
74     }
75 
76     // Check each vendor library for a dispatch stub.
77     glvnd_list_for_each_entry(vendor, vendorList, entry) {
78         addr = vendor->eglvc.getDispatchAddress(procName);
79         if (addr != NULL) {
80             break;
81         }
82     }
83     if (addr != NULL) {
84         index = __glvndWinsysDispatchAllocIndex(procName, addr);
85         if (index >= 0) {
86             glvnd_list_for_each_entry(vendor, vendorList, entry) {
87                 vendor->eglvc.setDispatchIndex(procName, index);
88             }
89         } else {
90             addr = NULL;
91         }
92     }
93 
94     __glvndPthreadFuncs.mutex_unlock(&dispatchIndexMutex);
95     return addr;
96 }
97 
__eglFetchDispatchEntry(__EGLvendorInfo * vendor,int index)98 __eglMustCastToProperFunctionPointerType __eglFetchDispatchEntry(
99         __EGLvendorInfo *vendor, int index)
100 {
101     __eglMustCastToProperFunctionPointerType addr = NULL;
102     const char *procName = NULL;
103 
104     addr = (__eglMustCastToProperFunctionPointerType)
105         __glvndWinsysVendorDispatchLookupFunc(vendor->dynDispatch, index);
106     if (addr != NULL) {
107         return addr;
108     }
109 
110     // Not seen before by this vendor: query the vendor for the right
111     // address to use.
112 
113     __glvndPthreadFuncs.mutex_lock(&dispatchIndexMutex);
114     procName = __glvndWinsysDispatchGetName(index);
115     __glvndPthreadFuncs.mutex_unlock(&dispatchIndexMutex);
116 
117     if (procName == NULL) {
118         // Not a valid function index.
119         return NULL;
120     }
121 
122     // Get the real address.
123     addr = vendor->eglvc.getProcAddress(procName);
124     if (addr != NULL) {
125         // Record the address in the vendor's hashtable. Note that if this
126         // fails, it's not fatal. It just means we'll have to call
127         // getProcAddress again the next time we need this function.
128         __glvndWinsysVendorDispatchAddFunc(vendor->dynDispatch, index, addr);
129     }
130     return addr;
131 }
132 
__eglGetVendorFromDisplay(EGLDisplay dpy)133 __EGLvendorInfo *__eglGetVendorFromDisplay(EGLDisplay dpy)
134 {
135     __EGLdisplayInfo *dpyInfo = __eglLookupDisplay(dpy);
136     if (dpyInfo != NULL) {
137         return dpyInfo->vendor;
138     } else {
139         return NULL;
140     }
141 }
142 
143 /**
144  * Allocates and initializes a __EGLdisplayInfoHash structure.
145  *
146  * The caller is responsible for adding the structure to the hashtable.
147  *
148  * \param dpy The display connection.
149  * \return A newly-allocated __EGLdisplayInfoHash structure, or NULL on error.
150  */
InitDisplayInfoEntry(EGLDisplay dpy,__EGLvendorInfo * vendor)151 static __EGLdisplayInfoHash *InitDisplayInfoEntry(EGLDisplay dpy, __EGLvendorInfo *vendor)
152 {
153     __EGLdisplayInfoHash *pEntry;
154 
155     pEntry = (__EGLdisplayInfoHash *) calloc(1, sizeof(*pEntry));
156     if (pEntry == NULL) {
157         return NULL;
158     }
159 
160     pEntry->info.dpy = dpy;
161     pEntry->info.vendor = vendor;
162 
163     return pEntry;
164 }
165 
__eglLookupDisplay(EGLDisplay dpy)166 __EGLdisplayInfo *__eglLookupDisplay(EGLDisplay dpy)
167 {
168     __EGLdisplayInfoHash *pEntry = NULL;
169 
170     if (dpy == EGL_NO_DISPLAY) {
171         return NULL;
172     }
173 
174     LKDHASH_RDLOCK(__eglDisplayInfoHash);
175     HASH_FIND_PTR(_LH(__eglDisplayInfoHash), &dpy, pEntry);
176     LKDHASH_UNLOCK(__eglDisplayInfoHash);
177 
178     if (pEntry != NULL) {
179         return &pEntry->info;
180     } else {
181         return NULL;
182     }
183 }
184 
__eglAddDisplay(EGLDisplay dpy,__EGLvendorInfo * vendor)185 __EGLdisplayInfo *__eglAddDisplay(EGLDisplay dpy, __EGLvendorInfo *vendor)
186 {
187     __EGLdisplayInfoHash *pEntry = NULL;
188 
189     if (dpy == EGL_NO_DISPLAY) {
190         return NULL;
191     }
192 
193     LKDHASH_WRLOCK(__eglDisplayInfoHash);
194     HASH_FIND_PTR(_LH(__eglDisplayInfoHash), &dpy, pEntry);
195     if (pEntry == NULL) {
196         pEntry = InitDisplayInfoEntry(dpy, vendor);
197         if (pEntry != NULL) {
198             HASH_ADD_PTR(_LH(__eglDisplayInfoHash), info.dpy, pEntry);
199         }
200     }
201 
202     LKDHASH_UNLOCK(__eglDisplayInfoHash);
203     if (pEntry != NULL && pEntry->info.vendor == vendor) {
204         return &pEntry->info;
205     } else {
206         return NULL;
207     }
208 }
209 
__eglFreeDisplay(EGLDisplay dpy)210 void __eglFreeDisplay(EGLDisplay dpy)
211 {
212     __EGLdisplayInfoHash *pEntry = NULL;
213 
214     LKDHASH_WRLOCK(__eglDisplayInfoHash);
215     HASH_FIND_PTR(_LH(__eglDisplayInfoHash), &dpy, pEntry);
216     if (pEntry != NULL) {
217         HASH_DEL(_LH(__eglDisplayInfoHash), pEntry);
218     }
219     LKDHASH_UNLOCK(__eglDisplayInfoHash);
220 
221     if (pEntry != NULL) {
222         free(pEntry);
223     }
224 }
225 
__eglMappingInit(void)226 void __eglMappingInit(void)
227 {
228     int i;
229     __eglInitDispatchStubs(&__eglExportsTable);
230     for (i=0; i<__EGL_DISPATCH_FUNC_COUNT; i++) {
231         int index = __glvndWinsysDispatchAllocIndex(
232                 __EGL_DISPATCH_FUNC_NAMES[i],
233                 __EGL_DISPATCH_FUNCS[i]);
234         if (index < 0) {
235             fprintf(stderr, "Could not allocate dispatch index array\n");
236             abort();
237         }
238         __EGL_DISPATCH_FUNC_INDICES[i] = index;
239     }
240 }
241 
__eglMappingTeardown(EGLBoolean doReset)242 void __eglMappingTeardown(EGLBoolean doReset)
243 {
244     if (doReset) {
245         //__EGLdisplayInfoHash *dpyInfoEntry, *dpyInfoTmp;
246 
247         /*
248          * If we're just doing fork recovery, we don't actually want to unload
249          * any currently loaded vendors _or_ remove any mappings (they should
250          * still be valid in the new process, and may be needed if the child
251          * tries using pointers/XIDs that were created in the parent).  Just
252          * reset the corresponding locks.
253          */
254         __glvndPthreadFuncs.mutex_init(&dispatchIndexMutex, NULL);
255         __glvndPthreadFuncs.rwlock_init(&__eglDisplayInfoHash.lock, NULL);
256     } else {
257         /* Tear down all hashtables used in this file */
258         LKDHASH_TEARDOWN(__EGLdisplayInfoHash,
259                          __eglDisplayInfoHash, NULL, NULL, EGL_FALSE);
260 
261         LKDHASH_TEARDOWN(__EGLdeviceInfo,
262                          __eglDeviceHash, NULL, NULL, EGL_FALSE);
263 
264        __glvndWinsysDispatchCleanup();
265     }
266 }
267 
__eglAddDevice(EGLDeviceEXT dev,__EGLvendorInfo * vendor)268 EGLBoolean __eglAddDevice(EGLDeviceEXT dev, __EGLvendorInfo *vendor)
269 {
270     __EGLdeviceInfo *devInfo = NULL;
271 
272     if (dev == EGL_NO_DEVICE_EXT) {
273         // If the handle is NULL, then just silently ignore it.
274         return EGL_TRUE;
275     }
276 
277     LKDHASH_WRLOCK(__eglDeviceHash);
278     HASH_FIND_PTR(_LH(__eglDeviceHash), &dev, devInfo);
279     if (devInfo == NULL) {
280         devInfo = malloc(sizeof(__EGLdeviceInfo));
281         if (devInfo == NULL) {
282             LKDHASH_UNLOCK(__eglDeviceHash);
283             return EGL_FALSE;
284         }
285         devInfo->handle = dev;
286         HASH_ADD_PTR(_LH(__eglDeviceHash), handle, devInfo);
287     }
288     devInfo->vendor = vendor;
289     LKDHASH_UNLOCK(__eglDeviceHash);
290     return EGL_TRUE;
291 }
292 
__eglGetVendorFromDevice(EGLDeviceEXT dev)293 __EGLvendorInfo *__eglGetVendorFromDevice(EGLDeviceEXT dev)
294 {
295     __EGLdeviceInfo *devInfo;
296     __EGLvendorInfo *vendor = NULL;
297 
298     LKDHASH_RDLOCK(__eglDeviceHash);
299     HASH_FIND_PTR(_LH(__eglDeviceHash), &dev, devInfo);
300     if (devInfo != NULL) {
301         vendor = devInfo->vendor;
302     } else {
303         vendor = NULL;
304     }
305     LKDHASH_UNLOCK(__eglDeviceHash);
306 
307     return vendor;
308 }
309 
310