1*1cddb830SAndroid Build Coastguard Worker /*
2*1cddb830SAndroid Build Coastguard Worker * Copyright (c) 2016-2020 The Khronos Group Inc.
3*1cddb830SAndroid Build Coastguard Worker *
4*1cddb830SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*1cddb830SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*1cddb830SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*1cddb830SAndroid Build Coastguard Worker *
8*1cddb830SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*1cddb830SAndroid Build Coastguard Worker *
10*1cddb830SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*1cddb830SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*1cddb830SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*1cddb830SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*1cddb830SAndroid Build Coastguard Worker * limitations under the License.
15*1cddb830SAndroid Build Coastguard Worker *
16*1cddb830SAndroid Build Coastguard Worker * OpenCL is a trademark of Apple Inc. used under license by Khronos.
17*1cddb830SAndroid Build Coastguard Worker */
18*1cddb830SAndroid Build Coastguard Worker
19*1cddb830SAndroid Build Coastguard Worker #include "icd.h"
20*1cddb830SAndroid Build Coastguard Worker #include "icd_envvars.h"
21*1cddb830SAndroid Build Coastguard Worker
22*1cddb830SAndroid Build Coastguard Worker #include <dlfcn.h>
23*1cddb830SAndroid Build Coastguard Worker #include <stdio.h>
24*1cddb830SAndroid Build Coastguard Worker #include <string.h>
25*1cddb830SAndroid Build Coastguard Worker #include <stdlib.h>
26*1cddb830SAndroid Build Coastguard Worker #include <sys/types.h>
27*1cddb830SAndroid Build Coastguard Worker #include <sys/stat.h>
28*1cddb830SAndroid Build Coastguard Worker #include <dirent.h>
29*1cddb830SAndroid Build Coastguard Worker #include <pthread.h>
30*1cddb830SAndroid Build Coastguard Worker #include <limits.h>
31*1cddb830SAndroid Build Coastguard Worker
32*1cddb830SAndroid Build Coastguard Worker static pthread_once_t initialized = PTHREAD_ONCE_INIT;
33*1cddb830SAndroid Build Coastguard Worker
34*1cddb830SAndroid Build Coastguard Worker /*
35*1cddb830SAndroid Build Coastguard Worker *
36*1cddb830SAndroid Build Coastguard Worker * Vendor enumeration functions
37*1cddb830SAndroid Build Coastguard Worker *
38*1cddb830SAndroid Build Coastguard Worker */
39*1cddb830SAndroid Build Coastguard Worker
40*1cddb830SAndroid Build Coastguard Worker typedef void khrIcdFileAdd(const char *);
41*1cddb830SAndroid Build Coastguard Worker
khrIcdOsDirEntryValidateAndAdd(const char * d_name,const char * path,const char * extension,khrIcdFileAdd addFunc)42*1cddb830SAndroid Build Coastguard Worker static inline void khrIcdOsDirEntryValidateAndAdd(const char *d_name, const char *path,
43*1cddb830SAndroid Build Coastguard Worker const char *extension, khrIcdFileAdd addFunc)
44*1cddb830SAndroid Build Coastguard Worker {
45*1cddb830SAndroid Build Coastguard Worker struct stat statBuff;
46*1cddb830SAndroid Build Coastguard Worker char* fileName = NULL;
47*1cddb830SAndroid Build Coastguard Worker
48*1cddb830SAndroid Build Coastguard Worker // make sure the file name ends in `extension` (eg. .icd, or .lay)
49*1cddb830SAndroid Build Coastguard Worker if (strlen(extension) > strlen(d_name))
50*1cddb830SAndroid Build Coastguard Worker {
51*1cddb830SAndroid Build Coastguard Worker return;
52*1cddb830SAndroid Build Coastguard Worker }
53*1cddb830SAndroid Build Coastguard Worker if (strcmp(d_name + strlen(d_name) - strlen(extension), extension))
54*1cddb830SAndroid Build Coastguard Worker {
55*1cddb830SAndroid Build Coastguard Worker return;
56*1cddb830SAndroid Build Coastguard Worker }
57*1cddb830SAndroid Build Coastguard Worker
58*1cddb830SAndroid Build Coastguard Worker // allocate space for the full path of the vendor library name
59*1cddb830SAndroid Build Coastguard Worker fileName = malloc(strlen(d_name) + strlen(path) + 2);
60*1cddb830SAndroid Build Coastguard Worker if (!fileName)
61*1cddb830SAndroid Build Coastguard Worker {
62*1cddb830SAndroid Build Coastguard Worker KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
63*1cddb830SAndroid Build Coastguard Worker return;
64*1cddb830SAndroid Build Coastguard Worker }
65*1cddb830SAndroid Build Coastguard Worker sprintf(fileName, "%s/%s", path, d_name);
66*1cddb830SAndroid Build Coastguard Worker
67*1cddb830SAndroid Build Coastguard Worker if (stat(fileName, &statBuff))
68*1cddb830SAndroid Build Coastguard Worker {
69*1cddb830SAndroid Build Coastguard Worker KHR_ICD_TRACE("Failed stat for: %s, continuing\n", fileName);
70*1cddb830SAndroid Build Coastguard Worker free(fileName);
71*1cddb830SAndroid Build Coastguard Worker return;
72*1cddb830SAndroid Build Coastguard Worker }
73*1cddb830SAndroid Build Coastguard Worker
74*1cddb830SAndroid Build Coastguard Worker if (S_ISREG(statBuff.st_mode) || S_ISLNK(statBuff.st_mode))
75*1cddb830SAndroid Build Coastguard Worker {
76*1cddb830SAndroid Build Coastguard Worker FILE *fin = NULL;
77*1cddb830SAndroid Build Coastguard Worker char* buffer = NULL;
78*1cddb830SAndroid Build Coastguard Worker long bufferSize = 0;
79*1cddb830SAndroid Build Coastguard Worker
80*1cddb830SAndroid Build Coastguard Worker // open the file and read its contents
81*1cddb830SAndroid Build Coastguard Worker fin = fopen(fileName, "r");
82*1cddb830SAndroid Build Coastguard Worker if (!fin)
83*1cddb830SAndroid Build Coastguard Worker {
84*1cddb830SAndroid Build Coastguard Worker free(fileName);
85*1cddb830SAndroid Build Coastguard Worker return;
86*1cddb830SAndroid Build Coastguard Worker }
87*1cddb830SAndroid Build Coastguard Worker fseek(fin, 0, SEEK_END);
88*1cddb830SAndroid Build Coastguard Worker bufferSize = ftell(fin);
89*1cddb830SAndroid Build Coastguard Worker
90*1cddb830SAndroid Build Coastguard Worker buffer = malloc(bufferSize+1);
91*1cddb830SAndroid Build Coastguard Worker if (!buffer)
92*1cddb830SAndroid Build Coastguard Worker {
93*1cddb830SAndroid Build Coastguard Worker free(fileName);
94*1cddb830SAndroid Build Coastguard Worker fclose(fin);
95*1cddb830SAndroid Build Coastguard Worker return;
96*1cddb830SAndroid Build Coastguard Worker }
97*1cddb830SAndroid Build Coastguard Worker memset(buffer, 0, bufferSize+1);
98*1cddb830SAndroid Build Coastguard Worker fseek(fin, 0, SEEK_SET);
99*1cddb830SAndroid Build Coastguard Worker if (bufferSize != (long)fread(buffer, 1, bufferSize, fin))
100*1cddb830SAndroid Build Coastguard Worker {
101*1cddb830SAndroid Build Coastguard Worker free(fileName);
102*1cddb830SAndroid Build Coastguard Worker free(buffer);
103*1cddb830SAndroid Build Coastguard Worker fclose(fin);
104*1cddb830SAndroid Build Coastguard Worker return;
105*1cddb830SAndroid Build Coastguard Worker }
106*1cddb830SAndroid Build Coastguard Worker // ignore a newline at the end of the file
107*1cddb830SAndroid Build Coastguard Worker if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';
108*1cddb830SAndroid Build Coastguard Worker
109*1cddb830SAndroid Build Coastguard Worker // load the string read from the file
110*1cddb830SAndroid Build Coastguard Worker addFunc(buffer);
111*1cddb830SAndroid Build Coastguard Worker
112*1cddb830SAndroid Build Coastguard Worker free(fileName);
113*1cddb830SAndroid Build Coastguard Worker free(buffer);
114*1cddb830SAndroid Build Coastguard Worker fclose(fin);
115*1cddb830SAndroid Build Coastguard Worker }
116*1cddb830SAndroid Build Coastguard Worker else
117*1cddb830SAndroid Build Coastguard Worker {
118*1cddb830SAndroid Build Coastguard Worker KHR_ICD_TRACE("File %s is not a regular file nor symbolic link, continuing\n", fileName);
119*1cddb830SAndroid Build Coastguard Worker free(fileName);
120*1cddb830SAndroid Build Coastguard Worker }
121*1cddb830SAndroid Build Coastguard Worker }
122*1cddb830SAndroid Build Coastguard Worker
123*1cddb830SAndroid Build Coastguard Worker struct dirElem
124*1cddb830SAndroid Build Coastguard Worker {
125*1cddb830SAndroid Build Coastguard Worker char *d_name;
126*1cddb830SAndroid Build Coastguard Worker unsigned char d_type;
127*1cddb830SAndroid Build Coastguard Worker };
128*1cddb830SAndroid Build Coastguard Worker
compareDirElem(const void * a,const void * b)129*1cddb830SAndroid Build Coastguard Worker static int compareDirElem(const void *a, const void *b)
130*1cddb830SAndroid Build Coastguard Worker {
131*1cddb830SAndroid Build Coastguard Worker // sort files the same way libc alpahnumerically sorts directory entries.
132*1cddb830SAndroid Build Coastguard Worker return strcoll(((struct dirElem *)a)->d_name, ((struct dirElem *)b)->d_name);
133*1cddb830SAndroid Build Coastguard Worker }
134*1cddb830SAndroid Build Coastguard Worker
khrIcdOsDirEnumerate(const char * path,const char * env,const char * extension,khrIcdFileAdd addFunc,int bSort)135*1cddb830SAndroid Build Coastguard Worker static inline void khrIcdOsDirEnumerate(const char *path, const char *env,
136*1cddb830SAndroid Build Coastguard Worker const char *extension,
137*1cddb830SAndroid Build Coastguard Worker khrIcdFileAdd addFunc, int bSort)
138*1cddb830SAndroid Build Coastguard Worker {
139*1cddb830SAndroid Build Coastguard Worker DIR *dir = NULL;
140*1cddb830SAndroid Build Coastguard Worker char* envPath = NULL;
141*1cddb830SAndroid Build Coastguard Worker
142*1cddb830SAndroid Build Coastguard Worker envPath = khrIcd_secure_getenv(env);
143*1cddb830SAndroid Build Coastguard Worker if (NULL != envPath)
144*1cddb830SAndroid Build Coastguard Worker {
145*1cddb830SAndroid Build Coastguard Worker path = envPath;
146*1cddb830SAndroid Build Coastguard Worker }
147*1cddb830SAndroid Build Coastguard Worker
148*1cddb830SAndroid Build Coastguard Worker dir = opendir(path);
149*1cddb830SAndroid Build Coastguard Worker if (NULL == dir)
150*1cddb830SAndroid Build Coastguard Worker {
151*1cddb830SAndroid Build Coastguard Worker KHR_ICD_TRACE("Failed to open path %s, continuing\n", path);
152*1cddb830SAndroid Build Coastguard Worker }
153*1cddb830SAndroid Build Coastguard Worker else
154*1cddb830SAndroid Build Coastguard Worker {
155*1cddb830SAndroid Build Coastguard Worker struct dirent *dirEntry = NULL;
156*1cddb830SAndroid Build Coastguard Worker
157*1cddb830SAndroid Build Coastguard Worker // attempt to load all files in the directory
158*1cddb830SAndroid Build Coastguard Worker if (bSort) {
159*1cddb830SAndroid Build Coastguard Worker // store the entries name and type in a buffer for sorting
160*1cddb830SAndroid Build Coastguard Worker size_t sz = 0;
161*1cddb830SAndroid Build Coastguard Worker size_t elemCount = 0;
162*1cddb830SAndroid Build Coastguard Worker size_t elemAlloc = 0;
163*1cddb830SAndroid Build Coastguard Worker struct dirElem *dirElems = NULL;
164*1cddb830SAndroid Build Coastguard Worker struct dirElem *newDirElems = NULL;
165*1cddb830SAndroid Build Coastguard Worker const size_t startupAlloc = 8;
166*1cddb830SAndroid Build Coastguard Worker
167*1cddb830SAndroid Build Coastguard Worker // start with a small buffer
168*1cddb830SAndroid Build Coastguard Worker dirElems = (struct dirElem *)malloc(startupAlloc*sizeof(struct dirElem));
169*1cddb830SAndroid Build Coastguard Worker if (NULL != dirElems) {
170*1cddb830SAndroid Build Coastguard Worker elemAlloc = startupAlloc;
171*1cddb830SAndroid Build Coastguard Worker for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) ) {
172*1cddb830SAndroid Build Coastguard Worker char *nameCopy = NULL;
173*1cddb830SAndroid Build Coastguard Worker
174*1cddb830SAndroid Build Coastguard Worker if (elemCount + 1 > elemAlloc) {
175*1cddb830SAndroid Build Coastguard Worker // double buffer size if necessary and possible
176*1cddb830SAndroid Build Coastguard Worker if (elemAlloc >= UINT_MAX/2)
177*1cddb830SAndroid Build Coastguard Worker break;
178*1cddb830SAndroid Build Coastguard Worker newDirElems = (struct dirElem *)realloc(dirElems, elemAlloc*2*sizeof(struct dirElem));
179*1cddb830SAndroid Build Coastguard Worker if (NULL == newDirElems)
180*1cddb830SAndroid Build Coastguard Worker break;
181*1cddb830SAndroid Build Coastguard Worker dirElems = newDirElems;
182*1cddb830SAndroid Build Coastguard Worker elemAlloc *= 2;
183*1cddb830SAndroid Build Coastguard Worker }
184*1cddb830SAndroid Build Coastguard Worker sz = strlen(dirEntry->d_name) + 1;
185*1cddb830SAndroid Build Coastguard Worker nameCopy = (char *)malloc(sz);
186*1cddb830SAndroid Build Coastguard Worker if (NULL == nameCopy)
187*1cddb830SAndroid Build Coastguard Worker break;
188*1cddb830SAndroid Build Coastguard Worker memcpy(nameCopy, dirEntry->d_name, sz);
189*1cddb830SAndroid Build Coastguard Worker dirElems[elemCount].d_name = nameCopy;
190*1cddb830SAndroid Build Coastguard Worker dirElems[elemCount].d_type = dirEntry->d_type;
191*1cddb830SAndroid Build Coastguard Worker elemCount++;
192*1cddb830SAndroid Build Coastguard Worker }
193*1cddb830SAndroid Build Coastguard Worker qsort(dirElems, elemCount, sizeof(struct dirElem), compareDirElem);
194*1cddb830SAndroid Build Coastguard Worker for (struct dirElem *elem = dirElems; elem < dirElems + elemCount; ++elem) {
195*1cddb830SAndroid Build Coastguard Worker khrIcdOsDirEntryValidateAndAdd(elem->d_name, path, extension, addFunc);
196*1cddb830SAndroid Build Coastguard Worker free(elem->d_name);
197*1cddb830SAndroid Build Coastguard Worker }
198*1cddb830SAndroid Build Coastguard Worker free(dirElems);
199*1cddb830SAndroid Build Coastguard Worker }
200*1cddb830SAndroid Build Coastguard Worker } else
201*1cddb830SAndroid Build Coastguard Worker // use system provided ordering
202*1cddb830SAndroid Build Coastguard Worker for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) )
203*1cddb830SAndroid Build Coastguard Worker khrIcdOsDirEntryValidateAndAdd(dirEntry->d_name, path, extension, addFunc);
204*1cddb830SAndroid Build Coastguard Worker
205*1cddb830SAndroid Build Coastguard Worker closedir(dir);
206*1cddb830SAndroid Build Coastguard Worker }
207*1cddb830SAndroid Build Coastguard Worker
208*1cddb830SAndroid Build Coastguard Worker if (NULL != envPath)
209*1cddb830SAndroid Build Coastguard Worker {
210*1cddb830SAndroid Build Coastguard Worker khrIcd_free_getenv(envPath);
211*1cddb830SAndroid Build Coastguard Worker }
212*1cddb830SAndroid Build Coastguard Worker }
213*1cddb830SAndroid Build Coastguard Worker
214*1cddb830SAndroid Build Coastguard Worker // go through the list of vendors in the two configuration files
khrIcdOsVendorsEnumerate(void)215*1cddb830SAndroid Build Coastguard Worker void khrIcdOsVendorsEnumerate(void)
216*1cddb830SAndroid Build Coastguard Worker {
217*1cddb830SAndroid Build Coastguard Worker khrIcdInitializeTrace();
218*1cddb830SAndroid Build Coastguard Worker khrIcdVendorsEnumerateEnv();
219*1cddb830SAndroid Build Coastguard Worker
220*1cddb830SAndroid Build Coastguard Worker khrIcdOsDirEnumerate(ICD_VENDOR_PATH, "OCL_ICD_VENDORS", ".icd", khrIcdVendorAdd, 0);
221*1cddb830SAndroid Build Coastguard Worker
222*1cddb830SAndroid Build Coastguard Worker #if defined(CL_ENABLE_LAYERS)
223*1cddb830SAndroid Build Coastguard Worker // system layers should be closer to the driver
224*1cddb830SAndroid Build Coastguard Worker khrIcdOsDirEnumerate(LAYER_PATH, "OPENCL_LAYER_PATH", ".lay", khrIcdLayerAdd, 1);
225*1cddb830SAndroid Build Coastguard Worker
226*1cddb830SAndroid Build Coastguard Worker khrIcdLayersEnumerateEnv();
227*1cddb830SAndroid Build Coastguard Worker #endif // defined(CL_ENABLE_LAYERS)
228*1cddb830SAndroid Build Coastguard Worker }
229*1cddb830SAndroid Build Coastguard Worker
230*1cddb830SAndroid Build Coastguard Worker // go through the list of vendors only once
khrIcdOsVendorsEnumerateOnce(void)231*1cddb830SAndroid Build Coastguard Worker void khrIcdOsVendorsEnumerateOnce(void)
232*1cddb830SAndroid Build Coastguard Worker {
233*1cddb830SAndroid Build Coastguard Worker pthread_once(&initialized, khrIcdOsVendorsEnumerate);
234*1cddb830SAndroid Build Coastguard Worker }
235*1cddb830SAndroid Build Coastguard Worker
236*1cddb830SAndroid Build Coastguard Worker /*
237*1cddb830SAndroid Build Coastguard Worker *
238*1cddb830SAndroid Build Coastguard Worker * Dynamic library loading functions
239*1cddb830SAndroid Build Coastguard Worker *
240*1cddb830SAndroid Build Coastguard Worker */
241*1cddb830SAndroid Build Coastguard Worker
242*1cddb830SAndroid Build Coastguard Worker // dynamically load a library. returns NULL on failure
khrIcdOsLibraryLoad(const char * libraryName)243*1cddb830SAndroid Build Coastguard Worker void *khrIcdOsLibraryLoad(const char *libraryName)
244*1cddb830SAndroid Build Coastguard Worker {
245*1cddb830SAndroid Build Coastguard Worker void* ret = dlopen (libraryName, RTLD_NOW);
246*1cddb830SAndroid Build Coastguard Worker if (NULL == ret)
247*1cddb830SAndroid Build Coastguard Worker {
248*1cddb830SAndroid Build Coastguard Worker KHR_ICD_TRACE("Failed to load driver because %s.\n", dlerror());
249*1cddb830SAndroid Build Coastguard Worker }
250*1cddb830SAndroid Build Coastguard Worker return ret;
251*1cddb830SAndroid Build Coastguard Worker }
252*1cddb830SAndroid Build Coastguard Worker
253*1cddb830SAndroid Build Coastguard Worker // get a function pointer from a loaded library. returns NULL on failure.
khrIcdOsLibraryGetFunctionAddress(void * library,const char * functionName)254*1cddb830SAndroid Build Coastguard Worker void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName)
255*1cddb830SAndroid Build Coastguard Worker {
256*1cddb830SAndroid Build Coastguard Worker return dlsym(library, functionName);
257*1cddb830SAndroid Build Coastguard Worker }
258*1cddb830SAndroid Build Coastguard Worker
259*1cddb830SAndroid Build Coastguard Worker // unload a library
khrIcdOsLibraryUnload(void * library)260*1cddb830SAndroid Build Coastguard Worker void khrIcdOsLibraryUnload(void *library)
261*1cddb830SAndroid Build Coastguard Worker {
262*1cddb830SAndroid Build Coastguard Worker dlclose(library);
263*1cddb830SAndroid Build Coastguard Worker }
264