Static-const-ify ICD loader info strings
[ocl-icd] / ocl_icd_loader.c
1 /**
2 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
3 Copyright (c) 2012, Vincent Danjean <Vincent.Danjean@ens-lyon.org>
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright notice, this
10    list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright notice,
12    this list of conditions and the following disclaimer in the documentation
13    and/or other materials provided with the distribution.
14
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <dirent.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <dlfcn.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include "config.h"
37 #ifdef USE_PTHREAD
38 #  include <pthread.h>
39 #endif
40 #pragma GCC diagnostic push
41 #  pragma GCC diagnostic ignored "-Wcpp"
42 #  define CL_USE_DEPRECATED_OPENCL_1_1_APIS
43 #  include <CL/opencl.h>
44 #pragma GCC diagnostic pop
45
46 #pragma GCC visibility push(hidden)
47
48 #include "ocl_icd_loader.h"
49 #define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD
50 #include "ocl_icd_debug.h"
51
52 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors"
53
54 int debug_ocl_icd_mask=0;
55
56 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
57
58 inline void dump_vendor_icd(const char* info, const struct vendor_icd *v) {
59   debug(D_DUMP, "%s %p={ num=%i, handle=%p, f=%p}\n", info,
60         v, v->num_platforms, v->dl_handle, v->ext_fn_ptr);
61 }
62
63 struct vendor_icd *_icds=NULL;
64 struct platform_icd *_picds=NULL;
65 static cl_uint _num_icds = 0;
66 cl_uint _num_picds = 0;
67
68 #ifdef DEBUG_OCL_ICD
69 #  define _clS(x) [-x] = #x
70 #  define MAX_CL_ERRORS (-CL_INVALID_DEVICE_PARTITION_COUNT)
71 static char const * const clErrorStr[MAX_CL_ERRORS+1] = {
72   _clS(CL_SUCCESS),
73   _clS(CL_DEVICE_NOT_FOUND),
74   _clS(CL_DEVICE_NOT_AVAILABLE),
75   _clS(CL_COMPILER_NOT_AVAILABLE),
76   _clS(CL_MEM_OBJECT_ALLOCATION_FAILURE),
77   _clS(CL_OUT_OF_RESOURCES),
78   _clS(CL_OUT_OF_HOST_MEMORY),
79   _clS(CL_PROFILING_INFO_NOT_AVAILABLE),
80   _clS(CL_MEM_COPY_OVERLAP),
81   _clS(CL_IMAGE_FORMAT_MISMATCH),
82   _clS(CL_IMAGE_FORMAT_NOT_SUPPORTED),
83   _clS(CL_BUILD_PROGRAM_FAILURE),
84   _clS(CL_MAP_FAILURE),
85   _clS(CL_MISALIGNED_SUB_BUFFER_OFFSET),
86   _clS(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST),
87   _clS(CL_COMPILE_PROGRAM_FAILURE),
88   _clS(CL_LINKER_NOT_AVAILABLE),
89   _clS(CL_LINK_PROGRAM_FAILURE),
90   _clS(CL_DEVICE_PARTITION_FAILED),
91   _clS(CL_KERNEL_ARG_INFO_NOT_AVAILABLE),
92   _clS(CL_INVALID_VALUE),
93   _clS(CL_INVALID_DEVICE_TYPE),
94   _clS(CL_INVALID_PLATFORM),
95   _clS(CL_INVALID_DEVICE),
96   _clS(CL_INVALID_CONTEXT),
97   _clS(CL_INVALID_QUEUE_PROPERTIES),
98   _clS(CL_INVALID_COMMAND_QUEUE),
99   _clS(CL_INVALID_HOST_PTR),
100   _clS(CL_INVALID_MEM_OBJECT),
101   _clS(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
102   _clS(CL_INVALID_IMAGE_SIZE),
103   _clS(CL_INVALID_SAMPLER),
104   _clS(CL_INVALID_BINARY),
105   _clS(CL_INVALID_BUILD_OPTIONS),
106   _clS(CL_INVALID_PROGRAM),
107   _clS(CL_INVALID_PROGRAM_EXECUTABLE),
108   _clS(CL_INVALID_KERNEL_NAME),
109   _clS(CL_INVALID_KERNEL_DEFINITION),
110   _clS(CL_INVALID_KERNEL),
111   _clS(CL_INVALID_ARG_INDEX),
112   _clS(CL_INVALID_ARG_VALUE),
113   _clS(CL_INVALID_ARG_SIZE),
114   _clS(CL_INVALID_KERNEL_ARGS),
115   _clS(CL_INVALID_WORK_DIMENSION),
116   _clS(CL_INVALID_WORK_GROUP_SIZE),
117   _clS(CL_INVALID_WORK_ITEM_SIZE),
118   _clS(CL_INVALID_GLOBAL_OFFSET),
119   _clS(CL_INVALID_EVENT_WAIT_LIST),
120   _clS(CL_INVALID_EVENT),
121   _clS(CL_INVALID_OPERATION),
122   _clS(CL_INVALID_GL_OBJECT),
123   _clS(CL_INVALID_BUFFER_SIZE),
124   _clS(CL_INVALID_MIP_LEVEL),
125   _clS(CL_INVALID_GLOBAL_WORK_SIZE),
126   _clS(CL_INVALID_PROPERTY),
127   _clS(CL_INVALID_IMAGE_DESCRIPTOR),
128   _clS(CL_INVALID_COMPILER_OPTIONS),
129   _clS(CL_INVALID_LINKER_OPTIONS),
130   _clS(CL_INVALID_DEVICE_PARTITION_COUNT)
131 };
132 #undef _clS
133 #endif
134
135 static char* _clerror2string (cl_int error) __attribute__((unused));
136 static char* _clerror2string (cl_int error) {
137 #ifdef DEBUG_OCL_ICD
138   if (-error > MAX_CL_ERRORS || error > 0) {
139     debug(D_WARN, "Unknown error code %d", error);
140     RETURN_STR("OpenCL Error");
141   }
142   const char *ret=clErrorStr[-error];
143   if (ret == NULL) {
144     debug(D_WARN, "Unknown error code %d", error);
145     RETURN_STR("OpenCL Error");
146   }
147   RETURN_STR(ret);
148 #else
149   static char number[15];
150   if (error==0) {
151     RETURN_STR("CL_SUCCESS");
152   }
153   snprintf(number, 15, "%i", error);
154   RETURN_STR(number);
155 #endif
156 }
157
158 static inline int _string_end_with_icd(const char* str) {
159   size_t len = strlen(str);
160   if( len<5 || strcmp(str + len - 4, ".icd" ) != 0 ) {
161     return 0;
162   }
163   return 1;
164 }
165
166 static inline int _string_with_slash(const char* str) {
167   return strchr(str, '/') != NULL;
168 }
169
170 static inline unsigned int _find_num_icds(DIR *dir) {
171   unsigned int num_icds = 0;
172   struct dirent *ent;
173   while( (ent=readdir(dir)) != NULL ){
174     if (_string_end_with_icd(ent->d_name)) {
175       num_icds++;
176     }
177   }
178   rewinddir(dir);
179   RETURN(num_icds);
180 }
181
182 static inline unsigned int _load_icd(int num_icds, const char* lib_path) {
183   unsigned int ret=0;
184   debug(D_LOG, "Loading ICD '%s'", lib_path);
185
186   _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
187   if(_icds[num_icds].dl_handle != NULL) {
188     debug(D_LOG, "ICD[%i] loaded", num_icds);
189     ret=1;
190   } else {
191     debug(D_WARN, "error while dlopening the IDL: '%s',\n  => skipping ICD", dlerror());
192   }
193   return ret;
194 }
195
196 static inline unsigned int _open_driver(unsigned int num_icds,
197                                         const char*dir_path, const char*file_path) {
198   char * lib_path;
199   char * err;
200   unsigned int lib_path_length;
201   if (dir_path != NULL) {
202     lib_path_length = strlen(dir_path) + strlen(file_path) + 2;
203     lib_path = malloc(lib_path_length*sizeof(char));
204     sprintf(lib_path,"%s/%s", dir_path, file_path);
205   } else {
206     lib_path_length = strlen(file_path) + 1;
207     lib_path = malloc(lib_path_length*sizeof(char));
208     sprintf(lib_path,"%s", file_path);
209   }
210   debug(D_LOG, "Considering file '%s'", lib_path);
211   FILE *f = fopen(lib_path,"r");
212   free(lib_path);
213   if (f==NULL) {
214     RETURN(num_icds);
215   }
216
217   fseek(f, 0, SEEK_END);
218   lib_path_length = ftell(f)+1;
219   fseek(f, 0, SEEK_SET);
220   if(lib_path_length == 1) {
221     debug(D_WARN, "File contents too short, skipping ICD");
222     fclose(f);
223     RETURN(num_icds);
224   }
225   lib_path = malloc(lib_path_length*sizeof(char));
226   err = fgets(lib_path, lib_path_length, f);
227   fclose(f);
228   if( err == NULL ) {
229     free(lib_path);
230     debug(D_WARN, "Error while loading file contents, skipping ICD");
231     RETURN(num_icds);
232   }
233
234   lib_path_length = strnlen(lib_path, lib_path_length);
235
236   if( lib_path[lib_path_length-1] == '\n' )
237     lib_path[lib_path_length-1] = '\0';
238
239   num_icds += _load_icd(num_icds, lib_path);
240
241   free(lib_path);
242   RETURN(num_icds);
243 }
244
245 static inline unsigned int _open_drivers(DIR *dir, const char* dir_path) {
246   unsigned int num_icds = 0;
247   struct dirent *ent;
248   while( (ent=readdir(dir)) != NULL ){
249     if(! _string_end_with_icd(ent->d_name)) {
250       continue;
251     }
252     num_icds = _open_driver(num_icds, dir_path, ent->d_name);
253
254   }
255   RETURN(num_icds);
256 }
257
258 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
259   void *addr1;
260   debug(D_LOG,"Looking for function %s",name);
261   addr1=dlsym(dlh, name);
262   if (addr1 == NULL) {
263     debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
264   }
265   void* addr2=NULL;
266   if (fn) {
267     addr2=(*fn)(name);
268     if (addr2 == NULL) {
269       debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
270     }
271 #ifdef DEBUG_OCL_ICD
272     if (addr1 && addr2 && addr1!=addr2) {
273       debug(D_WARN, "Function and symbol '%s' have different addresses (%p != %p)!", name, addr2, addr1);
274     }
275 #endif
276   }
277   if (!addr2) addr2=addr1;
278   RETURN(addr2);
279 }
280
281 static int _allocate_platforms(int req) {
282   static cl_uint allocated=0;
283   debug(D_LOG,"Requesting allocation for %d platforms",req);
284   if (allocated - _num_picds < req) {
285     if (allocated==0) {
286       _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
287     } else {
288       req = req - (allocated - _num_picds);
289       _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
290     }
291     allocated += req;
292   }
293   RETURN(allocated - _num_picds);
294 }
295
296 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
297                  cl_platform_id pid, cl_platform_info cname, char* sname) {
298   cl_int error;
299   size_t param_value_size_ret;
300   error = plt_info_ptr(pid, cname, 0, NULL, &param_value_size_ret);
301   if (error != CL_SUCCESS) {
302     debug(D_WARN, "Error %s while requesting %s in platform %p",
303           _clerror2string(error), sname, pid);
304     return NULL;
305   }
306   char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
307   if (param_value == NULL) {
308     debug(D_WARN, "Error in malloc while requesting %s in platform %p",
309           sname, pid);
310     return NULL;
311   }
312   error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
313   if (error != CL_SUCCESS){
314     free(param_value);
315     debug(D_WARN, "Error %s while requesting %s in platform %p",
316           _clerror2string(error), sname, pid);
317     return NULL;
318   }
319   RETURN_STR(param_value);
320 }
321
322 static void _count_devices(struct platform_icd *p) {
323   cl_int error;
324
325   /* Ensure they are 0 in case of errors */
326   p->ngpus = p->ncpus = p->ndevs = 0;
327
328   error = clGetDeviceIDs(p->pid, CL_DEVICE_TYPE_GPU, 0, NULL, &(p->ngpus));
329   if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND){
330     debug(D_WARN, "Error %s while counting GPU devices in platform %p",
331           _clerror2string(error), p->pid);
332   }
333
334   error = clGetDeviceIDs(p->pid, CL_DEVICE_TYPE_CPU, 0, NULL, &(p->ncpus));
335   if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND){
336     debug(D_WARN, "Error %s while counting CPU devices in platform %p",
337           _clerror2string(error), p->pid);
338   }
339
340   error = clGetDeviceIDs(p->pid, CL_DEVICE_TYPE_ALL, 0, NULL, &(p->ndevs));
341   if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND){
342     debug(D_WARN, "Error %s while counting ALL devices in platform %p",
343           _clerror2string(error), p->pid);
344   }
345
346 }
347
348 static int _cmp_platforms(const void *_a, const void *_b) {
349         const struct platform_icd *a=(const struct platform_icd *)_a;
350         const struct platform_icd *b=(const struct platform_icd *)_b;
351
352         /* sort first platforms handling max gpu */
353         if (a->ngpus > b->ngpus) return -1;
354         if (a->ngpus < b->ngpus) return 1;
355         /* sort next platforms handling max cpu */
356         if (a->ncpus > b->ncpus) return -1;
357         if (a->ncpus < b->ncpus) return 1;
358         /* sort then platforms handling max devices */
359         if (a->ndevs > b->ndevs) return -1;
360         if (a->ndevs < b->ndevs) return 1;
361         /* else consider platforms equal */
362         return 0;
363 }
364
365 static void _sort_platforms(struct platform_icd *picds, int npicds) {
366         debug(D_WARN, "Nb platefroms: %i", npicds);
367         if (npicds > 1) {
368                 char* ocl_sort=getenv("OCL_ICD_PLATFORM_SORT");
369                 if (ocl_sort!=NULL && !strcmp(ocl_sort, "none")) {
370                         debug(D_LOG, "Platform not sorted");
371                 } else {
372                         if (ocl_sort!=NULL && strcmp(ocl_sort, "devices")) {
373                                 debug(D_WARN, "Unknown platform sort algorithm requested: %s", ocl_sort);
374                                 debug(D_WARN, "Switching do the 'devices' algorithm");
375                         }
376                         int i;
377                         debug(D_LOG, "Platform sorted by GPU, CPU, DEV");
378                         for (i=0; i<npicds; i++) {
379                                 _count_devices(&picds[i]);
380                         }
381                         qsort(picds, npicds, sizeof(*picds),
382                               &_cmp_platforms);
383                 }
384         }
385 }
386
387 static inline void _find_and_check_platforms(cl_uint num_icds) {
388   cl_uint i;
389   _num_icds = 0;
390   for( i=0; i<num_icds; i++){
391     debug(D_LOG, "Checking ICD %i/%i", i, num_icds);
392     dump_vendor_icd("before looking for platforms", &_icds[i]);
393     struct vendor_icd *picd = &_icds[i];
394     void* dlh = _icds[i].dl_handle;
395     picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
396     clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
397       _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
398     clGetPlatformInfo_fn plt_info_ptr =
399       _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
400     if( picd->ext_fn_ptr == NULL
401         || plt_fn_ptr == NULL
402         || plt_info_ptr == NULL) {
403       debug(D_WARN, "Missing symbols in ICD, skipping it");
404       continue;
405     }
406     cl_uint num_platforms=0;
407     cl_int error;
408     error = (*plt_fn_ptr)(0, NULL, &num_platforms);
409     if( error != CL_SUCCESS || num_platforms == 0) {
410       debug(D_LOG, "No platform in ICD, skipping it");
411       continue;
412     }
413     cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
414     error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
415     if( error != CL_SUCCESS ){
416       free(platforms);
417       debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
418       continue;
419     }
420     cl_uint num_valid_platforms=0;
421     cl_uint j;
422     debug(D_LOG, "Try to load %d platforms", num_platforms);
423     if (_allocate_platforms(num_platforms) < num_platforms) {
424       free(platforms);
425       debug(D_WARN, "Not enought platform allocated. Skipping ICD");
426       continue;
427     }
428     for(j=0; j<num_platforms; j++) {
429       debug(D_LOG, "Checking platform %i", j);
430       struct platform_icd *p=&_picds[_num_picds];
431       char *param_value=NULL;
432       p->extension_suffix=NULL;
433       p->vicd=&_icds[i];
434       p->pid=platforms[j];
435 #ifdef DEBUG_OCL_ICD
436       if (debug_ocl_icd_mask & D_DUMP) {
437         int log=debug_ocl_icd_mask & D_TRACE;
438         debug_ocl_icd_mask &= ~D_TRACE;
439         dump_platform(p->vicd->ext_fn_ptr, p->pid);
440         debug_ocl_icd_mask |= log;
441       }
442 #endif
443       {
444               /* Allow to workaround a bug in the Intel ICD used
445                * with optirun (search for NVidia Optimus for more info)
446                */
447               const char* str=getenv("OCL_ICD_ASSUME_ICD_EXTENSION");
448               if (! str || str[0]==0) {
449                       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
450                       if (param_value == NULL){
451                               debug(D_WARN, "Skipping platform %i", j);
452                               continue;
453                       }
454                       debug(D_DUMP, "Supported extensions: %s", param_value);
455                       if( strstr(param_value, "cl_khr_icd") == NULL){
456                               free(param_value);
457                               debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
458                               continue;
459                       }
460                       free(param_value);
461               }
462       }
463       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
464       if (param_value == NULL){
465         debug(D_WARN, "Skipping platform %i", j);
466         continue;
467       }
468       p->extension_suffix = param_value;
469       debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
470 #ifdef DEBUG_OCL_ICD
471       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
472       if (param_value != NULL){
473         debug(D_DUMP, "Profile: %s", param_value);
474         free(param_value);
475       }
476       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
477       p->version = param_value;
478       if (param_value != NULL){
479         debug(D_DUMP, "Version: %s", param_value);
480         free(param_value);
481       }
482       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
483       if (param_value != NULL){
484         debug(D_DUMP, "Name: %s", param_value);
485         free(param_value);
486       }
487       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
488       if (param_value != NULL){
489         debug(D_DUMP, "Vendor: %s", param_value);
490         free(param_value);
491       }
492 #endif
493       num_valid_platforms++;
494       _num_picds++;
495     }
496     if( num_valid_platforms != 0 ) {
497       if ( _num_icds != i ) {
498         picd->dl_handle = dlh;
499       }
500       dump_vendor_icd("after looking for platforms", &_icds[_num_icds]);
501       _num_icds++;
502       picd->num_platforms = num_valid_platforms;
503     } else {
504       dlclose(dlh);
505     }
506     free(platforms);
507   }
508   _sort_platforms(&_picds[0], _num_picds);
509 }
510
511 static void __initClIcd( void ) {
512   debug_init();
513   cl_uint num_icds = 0;
514   int is_dir = 0;
515   DIR *dir = NULL;
516   const char* dir_path=getenv("OCL_ICD_VENDORS");
517   const char* vendor_path=getenv("OPENCL_VENDOR_PATH");
518   if (! vendor_path || vendor_path[0]==0) {
519     vendor_path=ETC_OPENCL_VENDORS;
520     debug(D_DUMP, "OPENCL_VENDOR_PATH unset or empty. Using hard-coded path '%s'", vendor_path);
521   } else {
522     debug(D_DUMP, "OPENCL_VENDOR_PATH set to '%s', using it", vendor_path);
523   }
524   if (! dir_path || dir_path[0]==0) {
525     dir_path=vendor_path;
526     debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using vendors path '%s'", dir_path);
527     is_dir=1;
528   }
529   if (!is_dir) {
530     struct stat buf;
531     int ret=stat(dir_path, &buf);
532     if (ret != 0 && errno != ENOENT) {
533       debug(D_WARN, "Cannot stat '%s'. Aborting", dir_path);
534     }
535     if (ret == 0 && S_ISDIR(buf.st_mode)) {
536       is_dir=1;
537     }
538   }
539
540   if (!is_dir) {
541     debug(D_LOG,"Only loading '%s' as an ICD", dir_path);
542     num_icds = 1;
543     dir=NULL;
544   } else {
545     debug(D_LOG,"Reading icd list from '%s'", dir_path);
546     dir = opendir(dir_path);
547     if(dir == NULL) {
548       if (errno == ENOTDIR) {
549         debug(D_DUMP, "%s is not a directory, trying to use it as a ICD libname",
550           dir_path);
551       }
552       goto abort;
553     }
554
555     num_icds = _find_num_icds(dir);
556     if(num_icds == 0) {
557       goto abort;
558     }
559   }
560
561   _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
562   if (_icds == NULL) {
563     goto abort;
564   }
565
566   if (!is_dir) {
567     if (_string_end_with_icd(dir_path)) {
568       num_icds = 0;
569       if (! _string_with_slash(dir_path)) {
570         num_icds = _open_driver(0, vendor_path, dir_path);
571       }
572       if (num_icds == 0) {
573         num_icds = _open_driver(0, NULL, dir_path);
574       }
575     } else {
576       num_icds = _load_icd(0, dir_path);
577     }
578   } else {
579     num_icds = _open_drivers(dir, dir_path);
580   }
581   if(num_icds == 0) {
582     goto abort;
583   }
584
585   _find_and_check_platforms(num_icds);
586   if(_num_icds == 0){
587     goto abort;
588   }
589
590   if (_num_icds < num_icds) {
591     _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
592   }
593   debug(D_WARN, "%d valid vendor(s)!", _num_icds);
594
595   if (dir != NULL){
596     closedir(dir);
597   }
598   return;
599  abort:
600   _num_icds = 0;
601   if (_icds) {
602     free(_icds);
603     _icds = NULL;
604   }
605   if (dir != NULL){
606     closedir(dir);
607   }
608   return;
609 }
610
611 #ifdef USE_PTHREAD
612 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
613 #else
614 static int gard=0;
615 #endif
616 volatile static __thread int in_init = 0;
617 volatile static cl_uint _initialized = 0;
618
619 static void _initClIcd_real( void ) {
620 #ifdef USE_PTHREAD
621   if (in_init) {
622     /* probably reentrency, in_init is a __thread variable */
623     debug(D_WARN, "Executing init while already in init!");
624   } else {
625     in_init=1;
626     __sync_synchronize();
627     pthread_once(&once_init, &__initClIcd);
628     __sync_synchronize();
629     in_init=0;
630   }
631 #else
632   if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
633     in_init=1;
634     __sync_synchronize();
635     __initClIcd();
636     __sync_synchronize();
637     in_init=0;
638   } else {
639     if (in_init) {
640       /* probably reentrency (could also be preemptive user-level threads). */
641     } else {
642       /* someone else started __initClIcd(). We wait until it ends. */
643       debug(D_WARN, "Waiting end of init");
644       while (!_initialized) {
645         __sync_synchronize();
646       }
647       debug(D_WARN, "Wait done");
648    }
649   }
650 #endif
651   _initialized = 1;
652 }
653
654 static inline void _initClIcd( void ) {
655   if( __builtin_expect (_initialized, 1) )
656     return;
657   _initClIcd_real();
658 }
659
660 cl_platform_id __attribute__((visibility("internal")))
661 getDefaultPlatformID() {
662   static cl_platform_id defaultPlatformID=NULL;
663   static int defaultSet=0;
664   _initClIcd();
665   if (! defaultSet) {
666     do {
667       if(_num_picds == 0) {
668         break;
669       }
670       const char *default_platform = getenv("OCL_ICD_DEFAULT_PLATFORM");
671       int num_default_platform;
672       char *end_scan;
673       if (! default_platform) {
674         num_default_platform = 0;
675       } else {
676         num_default_platform = strtol(default_platform, &end_scan, 10);
677         if (*default_platform == '\0' || *end_scan != '\0') {
678           break;
679         }
680       }
681       if (num_default_platform < 0 || num_default_platform >= _num_picds) {
682         break;
683       }
684       defaultPlatformID=_picds[num_default_platform].pid;
685     } while(0);
686     defaultSet=1;
687   }
688   return defaultPlatformID;
689 }
690
691 #pragma GCC visibility pop
692 #define hidden_alias(name) \
693   typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
694
695 typedef enum {
696   CL_ICDL_OCL_VERSION=1,
697   CL_ICDL_VERSION=2,
698   CL_ICDL_NAME=3,
699   CL_ICDL_VENDOR=4,
700 } cl_icdl_info;
701
702 static cl_int clGetICDLoaderInfoOCLICD(
703   cl_icdl_info     param_name,
704   size_t           param_value_size,
705   void *           param_value,
706   size_t *         param_value_size_ret)
707 {
708   static const char cl_icdl_ocl_version[] = "OpenCL " OCL_ICD_OPENCL_VERSION;
709   static const char cl_icdl_version[] = PACKAGE_VERSION;
710   static const char cl_icdl_name[] = PACKAGE_NAME;
711   static const char cl_icdl_vendor[] = "OCL Icd free software";
712
713   size_t size_string;
714   const char * string_p;
715 #define oclcase(name, NAME) \
716   case CL_ICDL_##NAME: \
717     string_p = cl_icdl_##name; \
718     size_string = sizeof(cl_icdl_##name); \
719     break
720
721   switch ( param_name ) {
722     oclcase(ocl_version,OCL_VERSION);
723     oclcase(version,VERSION);
724     oclcase(name,NAME);
725     oclcase(vendor,VENDOR);
726     default:
727       return CL_INVALID_VALUE;
728       break;
729   }
730 #undef oclcase
731   if( param_value != NULL ) {
732     if( size_string > param_value_size )
733       return CL_INVALID_VALUE;
734     memcpy(param_value, string_p, size_string);
735   }
736   if( param_value_size_ret != NULL )
737     *param_value_size_ret = size_string;
738   return CL_SUCCESS;
739 }
740
741 CL_API_ENTRY void * CL_API_CALL
742 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
743   debug_trace();
744   _initClIcd();
745   if( func_name == NULL )
746     return NULL;
747   cl_uint suffix_length;
748   cl_uint i;
749   void * return_value=NULL;
750   struct func_desc const * fn=&function_description[0];
751   int lenfn=strlen(func_name);
752   if (lenfn > 3 &&
753       (strcmp(func_name+lenfn-3, "KHR")==0 || strcmp(func_name+lenfn-3, "EXT")==0)) {
754     while (fn->name != NULL) {
755       if (strcmp(func_name, fn->name)==0)
756         RETURN(fn->addr);
757       fn++;
758     }
759   }
760   for(i=0; i<_num_picds; i++) {
761     suffix_length = strlen(_picds[i].extension_suffix);
762     if( suffix_length > strlen(func_name) )
763       continue;
764     if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
765       RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
766   }
767   if(strcmp(func_name, "clGetICDLoaderInfoOCLICD") == 0) {
768     return (void*)(void*(*)(void))(&clGetICDLoaderInfoOCLICD);
769   }
770   RETURN(return_value);
771 }
772 hidden_alias(clGetExtensionFunctionAddress);
773
774 CL_API_ENTRY cl_int CL_API_CALL
775 clGetPlatformIDs(cl_uint          num_entries,
776                  cl_platform_id * platforms,
777                  cl_uint *        num_platforms) CL_API_SUFFIX__VERSION_1_0 {
778   debug_trace();
779   _initClIcd();
780   if( platforms == NULL && num_platforms == NULL )
781     RETURN(CL_INVALID_VALUE);
782   if( num_entries == 0 && platforms != NULL )
783     RETURN(CL_INVALID_VALUE);
784   if( _num_icds == 0 || _num_picds == 0 ) {
785     if ( num_platforms != NULL )
786       *num_platforms = 0;
787     RETURN(CL_PLATFORM_NOT_FOUND_KHR);
788   }
789
790   cl_uint i;
791   if( num_platforms != NULL ){
792     *num_platforms = _num_picds;
793   }
794   if( platforms != NULL ) {
795     cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
796     for( i=0; i<n_platforms; i++) {
797       *(platforms++) = _picds[i].pid;
798     }
799   }
800   return CL_SUCCESS;
801 }
802 hidden_alias(clGetPlatformIDs);
803
804 #define RETURN_WITH_ERRCODE(errvar, errvalue, retvalue) \
805   do { \
806     if(errvar) { \
807       *errvar=errvalue; \
808     } \
809     RETURN(NULL); \
810   } while(0)
811
812 #define CHECK_PLATFORM(__pid) \
813   ({ \
814     cl_platform_id _pid=(__pid); \
815     int good=0; \
816     cl_uint j; \
817     for( j=0; j<_num_picds; j++) { \
818       if( _picds[j].pid == _pid) { \
819         good=1; \
820         break; \
821       } \
822     } \
823     good; \
824   })
825
826 CL_API_ENTRY cl_context CL_API_CALL
827 clCreateContext(const cl_context_properties *  properties ,
828                 cl_uint                        num_devices ,
829                 const cl_device_id *           devices ,
830                 void (CL_CALLBACK *  pfn_notify )(const char *, const void *, size_t, void *),
831                 void *                         user_data ,
832                 cl_int *                       errcode_ret ){
833   debug_trace();
834   _initClIcd();
835   cl_uint i=0;
836   if( properties != NULL){
837     while( properties[i] != 0 ) {
838       if( properties[i] == CL_CONTEXT_PLATFORM ) {
839         if((struct _cl_platform_id *) properties[i+1] == NULL) {
840           if(errcode_ret) {
841             *errcode_ret = CL_INVALID_PLATFORM;
842           }
843           RETURN(NULL);
844         } else {
845           if( !CHECK_PLATFORM((cl_platform_id) properties[i+1]) ) {
846             RETURN_WITH_ERRCODE(errcode_ret, CL_INVALID_PLATFORM, NULL);
847           }
848         }
849         RETURN(((struct _cl_platform_id *) properties[i+1])
850           ->dispatch->clCreateContext(properties, num_devices, devices,
851                         pfn_notify, user_data, errcode_ret));
852       }
853       i += 2;
854     }
855   }
856   if(devices == NULL || num_devices == 0) {
857     RETURN_WITH_ERRCODE(errcode_ret, CL_INVALID_VALUE, NULL);
858   }
859   if((struct _cl_device_id *)devices[0] == NULL) {
860     RETURN_WITH_ERRCODE(errcode_ret, CL_INVALID_DEVICE, NULL);
861   }
862   RETURN(((struct _cl_device_id *)devices[0])
863     ->dispatch->clCreateContext(properties, num_devices, devices,
864                   pfn_notify, user_data, errcode_ret));
865 }
866 hidden_alias(clCreateContext);
867
868 CL_API_ENTRY cl_context CL_API_CALL
869 clCreateContextFromType(const cl_context_properties *  properties ,
870                         cl_device_type                 device_type ,
871                         void (CL_CALLBACK *      pfn_notify )(const char *, const void *, size_t, void *),
872                         void *                         user_data ,
873                         cl_int *                       errcode_ret ){
874   debug_trace();
875   _initClIcd();
876   if(_num_picds == 0) {
877     goto out;
878   }
879   cl_uint i=0;
880   if( properties != NULL){
881     while( properties[i] != 0 ) {
882       if( properties[i] == CL_CONTEXT_PLATFORM ) {
883         if( (struct _cl_platform_id *) properties[i+1] == NULL ) {
884           goto out;
885         } else {
886           if( !CHECK_PLATFORM((cl_platform_id) properties[i+1]) ) {
887             goto out;
888           }
889         }
890         return ((struct _cl_platform_id *) properties[i+1])
891           ->dispatch->clCreateContextFromType(properties, device_type,
892                         pfn_notify, user_data, errcode_ret);
893       }
894       i += 2;
895     }
896   } else {
897     cl_platform_id default_platform=getDefaultPlatformID();
898     RETURN(default_platform->dispatch->clCreateContextFromType
899         (properties, device_type, pfn_notify, user_data, errcode_ret));
900   }
901  out:
902   RETURN_WITH_ERRCODE(errcode_ret, CL_INVALID_PLATFORM, NULL);
903 }
904 hidden_alias(clCreateContextFromType);
905
906 CL_API_ENTRY cl_int CL_API_CALL
907 clGetGLContextInfoKHR(const cl_context_properties *  properties ,
908                       cl_gl_context_info             param_name ,
909                       size_t                         param_value_size ,
910                       void *                         param_value ,
911                       size_t *                       param_value_size_ret ){
912   debug_trace();
913   _initClIcd();
914   cl_uint i=0;
915   if( properties != NULL){
916     while( properties[i] != 0 ) {
917       if( properties[i] == CL_CONTEXT_PLATFORM ) {
918         if( (struct _cl_platform_id *) properties[i+1] == NULL ) {
919           RETURN(CL_INVALID_PLATFORM);
920         } else {
921           if( !CHECK_PLATFORM((cl_platform_id) properties[i+1]) ) {
922             RETURN(CL_INVALID_PLATFORM);
923           }
924         }
925         RETURN(((struct _cl_platform_id *) properties[i+1])
926           ->dispatch->clGetGLContextInfoKHR(properties, param_name,
927                         param_value_size, param_value, param_value_size_ret));
928       }
929       i += 2;
930     }
931   }
932   RETURN(CL_INVALID_PLATFORM);
933 }
934 hidden_alias(clGetGLContextInfoKHR);
935
936 CL_API_ENTRY cl_int CL_API_CALL
937 clWaitForEvents(cl_uint              num_events ,
938                 const cl_event *     event_list ){
939   debug_trace();
940   if( num_events == 0 || event_list == NULL )
941     RETURN(CL_INVALID_VALUE);
942   if( (struct _cl_event *)event_list[0] == NULL )
943     RETURN(CL_INVALID_EVENT);
944   RETURN(((struct _cl_event *)event_list[0])
945     ->dispatch->clWaitForEvents(num_events, event_list));
946 }
947 hidden_alias(clWaitForEvents);
948
949 CL_API_ENTRY cl_int CL_API_CALL
950 clUnloadCompiler( void ){
951   debug_trace();
952   RETURN(CL_SUCCESS);
953 }
954 hidden_alias(clUnloadCompiler);