Add visibility("hidden") for all but public symbols
[ocl-icd] / ocl_icd_loader.c
1 /**
2 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
3 All rights reserved.
4       
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     
8 1. Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13         
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include <dirent.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <dlfcn.h>
31 #include <CL/opencl.h>
32
33 #pragma GCC visibility push(hidden)
34
35 #include "ocl_icd_loader.h"
36
37 typedef CL_API_ENTRY void * (CL_API_CALL *clGetExtensionFunctionAddress_fn)(const char * /* func_name */) CL_API_SUFFIX__VERSION_1_0;
38
39 static cl_uint _initialized = 0;
40 static cl_uint _num_valid_vendors = 0;
41 static cl_uint *_vendors_num_platforms = NULL;
42 static cl_platform_id **_vendors_platforms = NULL;
43 static void **_vendor_dl_handles = NULL;
44 static clGetExtensionFunctionAddress_fn *_ext_fn_ptr = NULL;
45 static char** _vendors_extension_suffixes = NULL;
46 static const char *_dir_path="/etc/OpenCL/vendors/";
47
48 static inline cl_uint _find_num_vendors(DIR *dir) {
49   cl_uint num_vendors = 0;
50   struct dirent *ent;
51   while( (ent=readdir(dir)) != NULL ){
52     if( strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 )
53       continue;
54     cl_uint d_name_len = strlen(ent->d_name);
55     if( strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
56       continue;
57 //    printf("%s%s\n", _dir_path, ent->d_name);
58     num_vendors++;
59   }
60   rewinddir(dir);
61   return num_vendors;
62 }
63
64 static inline cl_uint _open_drivers(DIR *dir) {
65   cl_uint num_vendors = 0;
66   struct dirent *ent;
67   while( (ent=readdir(dir)) != NULL ){
68     if( strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 )
69       continue;
70     cl_uint d_name_len = strlen(ent->d_name);
71     if( strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
72       continue;
73     char * lib_path;
74     char * err;
75     unsigned int lib_path_length = strlen(_dir_path) + strlen(ent->d_name) + 1;
76     lib_path = malloc(lib_path_length*sizeof(char));
77     sprintf(lib_path,"%s%s", _dir_path, ent->d_name);
78     FILE *f = fopen(lib_path,"r");
79     free(lib_path);
80
81     fseek(f, 0, SEEK_END);
82     lib_path_length = ftell(f)+1;
83     fseek(f, 0, SEEK_SET);
84     if(lib_path_length == 1) {
85       fclose(f);
86       continue;
87     }
88     lib_path = malloc(lib_path_length*sizeof(char));
89     err = fgets(lib_path, lib_path_length, f);
90     fclose(f);
91     if( err == NULL ) {
92       free(lib_path);
93       continue;
94     }
95
96     lib_path_length = strlen(lib_path);
97     
98     if( lib_path[lib_path_length-1] == '\n' )
99       lib_path[lib_path_length-1] = '\0';
100
101     _vendor_dl_handles[num_vendors] = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
102     free(lib_path);
103     if(_vendor_dl_handles[num_vendors] != NULL)      
104       num_vendors++;
105   }
106   return num_vendors;
107 }
108
109 static inline void _find_and_check_platforms(cl_uint num_vendors) {
110   cl_uint i;
111   _num_valid_vendors = 0;
112   for( i=0; i<num_vendors; i++){
113     cl_uint num_valid_platforms=0;
114     cl_uint num_platforms=0;
115     cl_platform_id *platforms;
116     cl_int error;
117     _ext_fn_ptr[_num_valid_vendors] = dlsym(_vendor_dl_handles[i], "clGetExtensionFunctionAddress");
118     clIcdGetPlatformIDsKHR_fn plt_fn_ptr;
119     if( _ext_fn_ptr[_num_valid_vendors] == NULL )
120       continue;
121     plt_fn_ptr = (*_ext_fn_ptr[_num_valid_vendors])("clIcdGetPlatformIDsKHR");
122     if( plt_fn_ptr == NULL )
123       continue;
124     error = (*plt_fn_ptr)(0, NULL, &num_platforms);
125     if( error != CL_SUCCESS || num_platforms == 0)
126       continue;
127     platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
128     error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
129     if( error != CL_SUCCESS ){
130       free(platforms);
131       continue;
132     }
133     _vendors_platforms[_num_valid_vendors] = (cl_platform_id *)malloc(num_platforms * sizeof(cl_platform_id));
134     cl_uint j;
135     for(j=0; j<num_platforms; j++) {
136       size_t param_value_size_ret;
137       error = ((struct _cl_platform_id *)platforms[j])->dispatch->clGetPlatformInfo(platforms[j], CL_PLATFORM_EXTENSIONS, 0, NULL, &param_value_size_ret);
138       if (error != CL_SUCCESS)
139         continue;
140       char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
141       error = ((struct _cl_platform_id *)platforms[j])->dispatch->clGetPlatformInfo(platforms[j], CL_PLATFORM_EXTENSIONS, param_value_size_ret, param_value, NULL);
142       if (error != CL_SUCCESS){
143         free(param_value);
144         continue;
145       }
146       if( strstr(param_value, "cl_khr_icd") == NULL){
147         free(param_value);
148         continue;
149       }
150       free(param_value);
151       error = ((struct _cl_platform_id *)platforms[j])->dispatch->clGetPlatformInfo(platforms[j], CL_PLATFORM_ICD_SUFFIX_KHR, 0, NULL, &param_value_size_ret);
152       if (error != CL_SUCCESS)
153         continue;
154       param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
155       error = ((struct _cl_platform_id *)platforms[j])->dispatch->clGetPlatformInfo(platforms[j], CL_PLATFORM_ICD_SUFFIX_KHR, param_value_size_ret, param_value, NULL);
156       if (error != CL_SUCCESS){
157         free(param_value);
158         continue;
159       }
160       _vendors_extension_suffixes[_num_valid_vendors] = param_value;
161       _vendors_platforms[_num_valid_vendors][num_valid_platforms] = platforms[j];
162       num_valid_platforms++;
163     }
164     if( num_valid_platforms != 0 ) {
165       _vendors_num_platforms[_num_valid_vendors] = num_valid_platforms;
166       _num_valid_vendors++;
167     } else {
168       free(_vendors_platforms[_num_valid_vendors]);
169       dlclose(_vendor_dl_handles[i]);
170     }
171     free(platforms);
172   }
173 }
174
175 static void _initClIcd( void ) {
176   if( _initialized )
177     return;
178   cl_uint num_vendors = 0;
179   DIR *dir;
180   dir = opendir(_dir_path);
181   if(dir == NULL) {
182     _num_valid_vendors = 0;
183     _initialized = 1;
184     return;
185   }
186
187   num_vendors = _find_num_vendors(dir);
188 //  printf("%d vendor(s)!\n", num_vendors);
189   if(num_vendors == 0) {
190     _num_valid_vendors = 0;
191     _initialized = 1;
192     return;
193   }
194
195   _vendor_dl_handles = (void **)malloc(num_vendors * sizeof(void *));
196   num_vendors = _open_drivers(dir);
197 //  printf("%d vendor(s)!\n", num_vendors);
198   if(num_vendors == 0) {
199     free( _vendor_dl_handles );
200     _num_valid_vendors = 0;
201     _initialized = 1;
202     return;
203   }
204
205   _ext_fn_ptr = (clGetExtensionFunctionAddress_fn *)malloc(num_vendors * sizeof(clGetExtensionFunctionAddress_fn));
206   _vendors_extension_suffixes = (char **) malloc (sizeof(char *) * num_vendors);
207   _vendors_num_platforms = (cl_uint *)malloc(num_vendors * sizeof(cl_uint));
208   _vendors_platforms = (cl_platform_id **)malloc(num_vendors * sizeof(cl_platform_id *));
209   _find_and_check_platforms(num_vendors);
210   if(_num_valid_vendors == 0){
211     free( _vendor_dl_handles );
212     free( _ext_fn_ptr );
213     free( _vendors_extension_suffixes );
214     free( _vendors_platforms );
215     free( _vendors_num_platforms );
216   }
217 //  printf("%d valid vendor(s)!\n", _num_valid_vendors);
218   _initialized = 1;
219 }
220
221 #pragma GCC visibility pop
222
223 CL_API_ENTRY void * CL_API_CALL clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
224   if( !_initialized )
225     _initClIcd();
226   if( func_name == NULL )
227     return NULL;
228   cl_uint suffix_length;
229   cl_uint i;
230   void * return_value=NULL;
231   struct func_desc const * fn=&function_description[0];
232   while (fn->name != NULL) {
233     if (strcmp(func_name, fn->name)==0)
234       return fn->addr;
235     fn++;
236   }
237   for(i=0; i<_num_valid_vendors; i++) {
238     suffix_length = strlen(_vendors_extension_suffixes[i]);
239     if( suffix_length > strlen(func_name) )
240       continue;
241     if(strcmp(_vendors_extension_suffixes[i], &func_name[strlen(func_name)-suffix_length]) == 0)
242       return (*_ext_fn_ptr[i])(func_name);
243   }
244   return return_value;
245 }
246
247 CL_API_ENTRY cl_int CL_API_CALL
248 clGetPlatformIDs(cl_uint          num_entries,
249                  cl_platform_id * platforms,
250                  cl_uint *        num_platforms) CL_API_SUFFIX__VERSION_1_0 {
251   if( !_initialized )
252     _initClIcd();
253   if( platforms == NULL && num_platforms == NULL )
254     return CL_INVALID_VALUE;
255   if( num_entries == 0 && platforms != NULL )
256     return CL_INVALID_VALUE;
257   if( _num_valid_vendors == 0)
258     return CL_PLATFORM_NOT_FOUND_KHR;
259
260   cl_uint i;
261   cl_uint n_platforms=0;
262   for(i=0; i<_num_valid_vendors; i++) {
263     n_platforms += _vendors_num_platforms[i];
264   }
265   if( num_platforms != NULL ){
266     *num_platforms = n_platforms;
267   }
268   if( platforms != NULL ) {
269     n_platforms = n_platforms < num_entries ? n_platforms : num_entries;
270     for( i=0; i<_num_valid_vendors; i++) {
271       cl_uint j;
272       for(j=0; j<_vendors_num_platforms[i]; j++) {
273         *(platforms++) = _vendors_platforms[i][j];
274         n_platforms--;
275         if( n_platforms == 0 )
276           return CL_SUCCESS;
277       }
278     }
279   }
280   return CL_SUCCESS;
281 }
282
283