Improve OCL_ICD_VENDORS envvar
[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__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
57 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
58
59
60 struct vendor_icd {
61   cl_uint       num_platforms;
62   cl_uint       first_platform;
63   void *        dl_handle;
64   clGetExtensionFunctionAddress_fn ext_fn_ptr;
65 };
66
67 struct platform_icd {
68   char *         extension_suffix;
69   char *         version;
70   struct vendor_icd *vicd;
71   cl_platform_id pid;
72 };
73
74 struct vendor_icd *_icds=NULL;
75 struct platform_icd *_picds=NULL;
76 static cl_uint _num_icds = 0;
77 static cl_uint _num_picds = 0;
78
79 #if DEBUG_OCL_ICD
80 #  define _clS(x) [-x] = #x
81 #  define MAX_CL_ERRORS CL_INVALID_DEVICE_PARTITION_COUNT
82 static char const * const clErrorStr[-MAX_CL_ERRORS+1] = {
83   _clS(CL_SUCCESS),
84   _clS(CL_DEVICE_NOT_FOUND),
85   _clS(CL_DEVICE_NOT_AVAILABLE),
86   _clS(CL_COMPILER_NOT_AVAILABLE),
87   _clS(CL_MEM_OBJECT_ALLOCATION_FAILURE),
88   _clS(CL_OUT_OF_RESOURCES),
89   _clS(CL_OUT_OF_HOST_MEMORY),
90   _clS(CL_PROFILING_INFO_NOT_AVAILABLE),
91   _clS(CL_MEM_COPY_OVERLAP),
92   _clS(CL_IMAGE_FORMAT_MISMATCH),
93   _clS(CL_IMAGE_FORMAT_NOT_SUPPORTED),
94   _clS(CL_BUILD_PROGRAM_FAILURE),
95   _clS(CL_MAP_FAILURE),
96   _clS(CL_MISALIGNED_SUB_BUFFER_OFFSET),
97   _clS(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST),
98   _clS(CL_COMPILE_PROGRAM_FAILURE),
99   _clS(CL_LINKER_NOT_AVAILABLE),
100   _clS(CL_LINK_PROGRAM_FAILURE),
101   _clS(CL_DEVICE_PARTITION_FAILED),
102   _clS(CL_KERNEL_ARG_INFO_NOT_AVAILABLE),
103   _clS(CL_INVALID_VALUE),
104   _clS(CL_INVALID_DEVICE_TYPE),
105   _clS(CL_INVALID_PLATFORM),
106   _clS(CL_INVALID_DEVICE),
107   _clS(CL_INVALID_CONTEXT),
108   _clS(CL_INVALID_QUEUE_PROPERTIES),
109   _clS(CL_INVALID_COMMAND_QUEUE),
110   _clS(CL_INVALID_HOST_PTR),
111   _clS(CL_INVALID_MEM_OBJECT),
112   _clS(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
113   _clS(CL_INVALID_IMAGE_SIZE),
114   _clS(CL_INVALID_SAMPLER),
115   _clS(CL_INVALID_BINARY),
116   _clS(CL_INVALID_BUILD_OPTIONS),
117   _clS(CL_INVALID_PROGRAM),
118   _clS(CL_INVALID_PROGRAM_EXECUTABLE),
119   _clS(CL_INVALID_KERNEL_NAME),
120   _clS(CL_INVALID_KERNEL_DEFINITION),
121   _clS(CL_INVALID_KERNEL),
122   _clS(CL_INVALID_ARG_INDEX),
123   _clS(CL_INVALID_ARG_VALUE),
124   _clS(CL_INVALID_ARG_SIZE),
125   _clS(CL_INVALID_KERNEL_ARGS),
126   _clS(CL_INVALID_WORK_DIMENSION),
127   _clS(CL_INVALID_WORK_GROUP_SIZE),
128   _clS(CL_INVALID_WORK_ITEM_SIZE),
129   _clS(CL_INVALID_GLOBAL_OFFSET),
130   _clS(CL_INVALID_EVENT_WAIT_LIST),
131   _clS(CL_INVALID_EVENT),
132   _clS(CL_INVALID_OPERATION),
133   _clS(CL_INVALID_GL_OBJECT),
134   _clS(CL_INVALID_BUFFER_SIZE),
135   _clS(CL_INVALID_MIP_LEVEL),
136   _clS(CL_INVALID_GLOBAL_WORK_SIZE),
137   _clS(CL_INVALID_PROPERTY),
138   _clS(CL_INVALID_IMAGE_DESCRIPTOR),
139   _clS(CL_INVALID_COMPILER_OPTIONS),
140   _clS(CL_INVALID_LINKER_OPTIONS),
141   _clS(CL_INVALID_DEVICE_PARTITION_COUNT)
142 };
143 #undef _clS
144 #endif
145
146 static char* _clerror2string (cl_int error) __attribute__((unused));
147 static char* _clerror2string (cl_int error) {
148 #if DEBUG_OCL_ICD
149   if (-error > MAX_CL_ERRORS || error > 0) {
150     debug(D_WARN, "Unknown error code %d", error);
151     RETURN_STR("OpenCL Error");
152   }
153   const char *ret=clErrorStr[-error];
154   if (ret == NULL) {
155     debug(D_WARN, "Unknown error code %d", error);
156     RETURN_STR("OpenCL Error");
157   }
158   RETURN_STR(ret);
159 #else
160   static char number[15];
161   if (error==0) {
162     RETURN_STR("CL_SUCCESS");
163   }
164   snprintf(number, 15, "%i", error);
165   RETURN_STR(number);
166 #endif
167 }
168
169 static inline int _string_end_with_icd(const char* str) {
170   size_t len = strlen(str);
171   if( len<5 || strcmp(str + len - 4, ".icd" ) != 0 ) {
172     return 0;
173   }
174   return 1;
175 }
176
177 static inline int _string_with_slash(const char* str) {
178   return strchr(str, '/') != NULL;
179 }
180
181 static inline unsigned int _find_num_icds(DIR *dir) {
182   unsigned int num_icds = 0;
183   struct dirent *ent;
184   while( (ent=readdir(dir)) != NULL ){
185     if (_string_end_with_icd(ent->d_name)) {
186       num_icds++;
187     }
188   }
189   rewinddir(dir);
190   RETURN(num_icds);
191 }
192
193 static inline unsigned int _load_icd(int num_icds, const char* lib_path) {
194   unsigned int ret=0;
195   debug(D_LOG, "Loading ICD '%s'", lib_path);
196
197   _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
198   if(_icds[num_icds].dl_handle != NULL) {
199     debug(D_LOG, "ICD[%i] loaded", num_icds);
200     ret=1;
201   } else {
202     debug(D_WARN, "error while dlopening the IDL: '%s',\n  => skipping ICD", dlerror());
203   }
204   return ret;
205 }
206
207 static inline unsigned int _open_driver(unsigned int num_icds,
208                                         const char*dir_path, const char*file_path) {
209   char * lib_path;
210   char * err;
211   unsigned int lib_path_length;
212   if (dir_path != NULL) {
213     lib_path_length = strlen(dir_path) + strlen(file_path) + 2;
214     lib_path = malloc(lib_path_length*sizeof(char));
215     sprintf(lib_path,"%s/%s", dir_path, file_path);
216   } else {
217     lib_path_length = strlen(file_path) + 1;
218     lib_path = malloc(lib_path_length*sizeof(char));
219     sprintf(lib_path,"%s", file_path);
220   }
221   debug(D_LOG, "Considering file '%s'", lib_path);
222   FILE *f = fopen(lib_path,"r");
223   free(lib_path);
224   if (f==NULL) {
225     RETURN(num_icds);
226   }
227   
228   fseek(f, 0, SEEK_END);
229   lib_path_length = ftell(f)+1;
230   fseek(f, 0, SEEK_SET);
231   if(lib_path_length == 1) {
232     debug(D_WARN, "File contents too short, skipping ICD");
233     fclose(f);
234     RETURN(num_icds);
235   }
236   lib_path = malloc(lib_path_length*sizeof(char));
237   err = fgets(lib_path, lib_path_length, f);
238   fclose(f);
239   if( err == NULL ) {
240     free(lib_path);
241     debug(D_WARN, "Error while loading file contents, skipping ICD");
242     RETURN(num_icds);
243   }
244
245   lib_path_length = strlen(lib_path);
246   
247   if( lib_path[lib_path_length-1] == '\n' )
248     lib_path[lib_path_length-1] = '\0';
249
250   num_icds += _load_icd(num_icds, lib_path);
251
252   free(lib_path);
253   RETURN(num_icds);
254 }
255
256 static inline unsigned int _open_drivers(DIR *dir, const char* dir_path) {
257   unsigned int num_icds = 0;
258   struct dirent *ent;
259   while( (ent=readdir(dir)) != NULL ){
260     if(! _string_end_with_icd(ent->d_name)) {
261       continue;
262     }
263     num_icds = _open_driver(num_icds, dir_path, ent->d_name);
264
265   }
266   RETURN(num_icds);
267 }
268
269 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
270   void *addr1;
271   debug(D_LOG,"Looking for function %s",name);
272   addr1=dlsym(dlh, name);
273   if (addr1 == NULL) {
274     debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
275   }
276   void* addr2=NULL;
277   if (fn) {
278     addr2=(*fn)(name);
279     if (addr2 == NULL) {
280       debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
281     }
282 #if DEBUG_OCL_ICD
283     if (addr1 && addr2 && addr1!=addr2) {
284       debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
285     }
286 #endif
287   }
288   if (!addr2) addr2=addr1;
289   RETURN(addr2);
290 }
291
292 static int _allocate_platforms(int req) {
293   static cl_uint allocated=0;
294   debug(D_LOG,"Requesting allocation for %d platforms",req);
295   if (allocated - _num_picds < req) {
296     if (allocated==0) {
297       _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
298     } else {
299       req = req - (allocated - _num_picds);
300       _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
301     }
302     allocated += req;
303   }
304   RETURN(allocated - _num_picds);
305 }
306
307 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
308                  cl_platform_id pid, cl_platform_info cname, char* sname) {
309   cl_int error;
310   size_t param_value_size_ret;
311   error = plt_info_ptr(pid, cname, 0, NULL, &param_value_size_ret);
312   if (error != CL_SUCCESS) {
313     debug(D_WARN, "Error %s while requesting %s in platform %p",
314           _clerror2string(error), sname, pid);
315     return NULL;
316   }
317   char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
318   if (param_value == NULL) {
319     debug(D_WARN, "Error in malloc while requesting %s in platform %p",
320           sname, pid);
321     return NULL;
322   }
323   error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
324   if (error != CL_SUCCESS){
325     free(param_value);
326     debug(D_WARN, "Error %s while requesting %s in platform %p",
327           _clerror2string(error), sname, pid);
328     return NULL;
329   }
330   RETURN_STR(param_value);
331 }
332
333 static inline void _find_and_check_platforms(cl_uint num_icds) {
334   cl_uint i;
335   _num_icds = 0;
336   for( i=0; i<num_icds; i++){
337     debug(D_LOG, "Checking ICD %i", i);
338     struct vendor_icd *picd = &_icds[_num_icds];
339     void* dlh = _icds[i].dl_handle;
340     picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
341     clIcdGetPlatformIDsKHR_fn plt_fn_ptr = 
342       _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
343     clGetPlatformInfo_fn plt_info_ptr = 
344       _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
345     if( picd->ext_fn_ptr == NULL
346         || plt_fn_ptr == NULL
347         || plt_info_ptr == NULL) {
348       debug(D_WARN, "Missing symbols in ICD, skipping it");
349       continue;
350     }
351     cl_uint num_platforms=0;
352     cl_int error;
353     error = (*plt_fn_ptr)(0, NULL, &num_platforms);
354     if( error != CL_SUCCESS || num_platforms == 0) {
355       debug(D_LOG, "No platform in ICD, skipping it");
356       continue;
357     }
358     cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
359     error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
360     if( error != CL_SUCCESS ){
361       free(platforms);
362       debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
363       continue;
364     }
365     cl_uint num_valid_platforms=0;
366     cl_uint j;
367     debug(D_LOG, "Try to load %d plateforms", num_platforms);
368     if (_allocate_platforms(num_platforms) < num_platforms) {
369       free(platforms);
370       debug(D_WARN, "Not enought platform allocated. Skipping ICD");
371       continue;
372     }
373     for(j=0; j<num_platforms; j++) {
374       debug(D_LOG, "Checking platform %i", j);
375       struct platform_icd *p=&_picds[_num_picds];
376       p->extension_suffix=NULL;
377       p->vicd=&_icds[i];
378       p->pid=platforms[j];
379 #if DEBUG_OCL_ICD
380       if (debug_ocl_icd_mask & D_DUMP) {
381         int log=debug_ocl_icd_mask & D_TRACE;
382         debug_ocl_icd_mask &= ~D_TRACE;
383         dump_platform(p->vicd->ext_fn_ptr, p->pid);
384         debug_ocl_icd_mask |= log;
385       }
386 #endif
387       char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
388       if (param_value == NULL){
389         debug(D_WARN, "Skipping platform %i", j);
390         continue;
391       }
392       debug(D_DUMP, "Supported extensions: %s", param_value);
393       if( strstr(param_value, "cl_khr_icd") == NULL){
394         free(param_value);
395         debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
396         continue;
397       }
398       free(param_value);
399       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
400       if (param_value == NULL){
401         debug(D_WARN, "Skipping platform %i", j);
402         continue;
403       }
404       p->extension_suffix = param_value;
405       debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
406 #if DEBUG_OCL_ICD
407       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
408       if (param_value != NULL){
409         debug(D_DUMP, "Profile: %s", param_value);
410         free(param_value);
411       }
412 #endif
413       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
414       p->version = param_value;
415       if (param_value != NULL){
416         debug(D_DUMP, "Version: %s", param_value);
417         free(param_value);
418       }
419 #if DEBUG_OCL_ICD
420       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
421       if (param_value != NULL){
422         debug(D_DUMP, "Name: %s", param_value);
423         free(param_value);
424       }
425       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
426       if (param_value != NULL){
427         debug(D_DUMP, "Vendor: %s", param_value);
428         free(param_value);
429       }
430 #endif
431       num_valid_platforms++;
432       _num_picds++;
433     }
434     if( num_valid_platforms != 0 ) {
435       if ( _num_icds != i ) {
436         picd->dl_handle = dlh;
437       }
438       _num_icds++;
439       picd->num_platforms = num_valid_platforms;
440       _icds[i].first_platform = _num_picds - num_valid_platforms;
441     } else {
442       dlclose(dlh);
443     }
444     free(platforms);
445   }
446 }
447
448 static void __initClIcd( void ) {
449   debug_init();
450   cl_uint num_icds = 0;
451   int is_dir = 0;
452   DIR *dir;
453   const char* dir_path=getenv("OCL_ICD_VENDORS");
454   if (! dir_path || dir_path[0]==0) {
455     debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
456     dir_path=ETC_OPENCL_VENDORS;
457     is_dir=1;
458   }
459   if (!is_dir) {
460     struct stat buf;
461     int ret=stat(dir_path, &buf);
462     if (ret != 0 && errno != ENOENT) {
463       debug(D_WARN, "Cannot stat '%s'. Aborting", dir_path);
464     }
465     if (ret == 0 && S_ISDIR(buf.st_mode)) {
466       is_dir=1;
467     }
468   }
469   
470   if (!is_dir) {
471     debug(D_LOG,"Only loading '%s' as an ICD", dir_path);
472     num_icds = 1;
473     dir=NULL;
474   } else {
475     debug(D_LOG,"Reading icd list from '%s'", dir_path);
476     dir = opendir(dir_path);
477     if(dir == NULL) {
478       if (errno == ENOTDIR) {
479         debug(D_DUMP, "%s is not a directory, trying to use it as a ICD libname",
480         dir_path);
481       }
482       goto abort;
483     }
484
485     num_icds = _find_num_icds(dir);
486     if(num_icds == 0) {
487       goto abort;
488     }
489   }
490
491   _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
492   if (_icds == NULL) {
493     goto abort;
494   }
495   
496   if (!is_dir) {
497     if (_string_end_with_icd(dir_path)) {
498       num_icds = 0;
499       if (! _string_with_slash(dir_path)) {
500         num_icds = _open_driver(0, ETC_OPENCL_VENDORS, dir_path);
501       }
502       if (num_icds == 0) {
503         num_icds = _open_driver(0, NULL, dir_path);
504       }
505     } else {
506       num_icds = _load_icd(0, dir_path);
507     }
508   } else {
509     num_icds = _open_drivers(dir, dir_path);
510   }
511   if(num_icds == 0) {
512     goto abort;
513   }
514
515   _find_and_check_platforms(num_icds);
516   if(_num_icds == 0){
517     goto abort;
518   }
519
520   if (_num_icds < num_icds) {
521     _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
522   }
523   debug(D_WARN, "%d valid vendor(s)!", _num_icds);
524   return;
525  abort:
526   _num_icds = 0;
527   if (_icds) {
528     free(_icds);
529     _icds = NULL;
530   }
531   return;
532 }
533
534 #ifdef USE_PTHREAD
535 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
536 #else
537 static int gard=0;
538 #endif
539 volatile static __thread int in_init = 0;
540 volatile static cl_uint _initialized = 0;
541
542 static inline void __attribute__((constructor)) _initClIcd( void ) {
543   if( _initialized )
544     return;
545 #ifdef USE_PTHREAD
546   if (in_init) {
547     /* probably reentrency */
548   } else {
549     in_init=1;
550     __sync_synchronize();
551     pthread_once(&once_init, &__initClIcd);
552     __sync_synchronize();
553     in_init=0;
554   }
555 #else
556   if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
557     in_init=1;
558     __sync_synchronize();
559     __initClIcd();
560     __sync_synchronize();
561     in_init=0;
562   } else {
563     if (in_init) {
564       /* probably reentrency (could also be user threads). */
565     } else {
566       /* someone else started __initClIcd(). We wait until its end. */
567       debug(D_WARN, "Waiting end of init");
568       while (!_initialized) ;
569       debug(D_WARN, "Wait done");
570    }
571   }
572 #endif
573   _initialized = 1;
574 }
575
576 #pragma GCC visibility pop
577 #define hidden_alias(name) \
578   typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
579
580 CL_API_ENTRY void * CL_API_CALL
581 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
582   debug_trace();
583   _initClIcd();
584   if( func_name == NULL )
585     return NULL;
586   cl_uint suffix_length;
587   cl_uint i;
588   void * return_value=NULL;
589   struct func_desc const * fn=&function_description[0];
590   while (fn->name != NULL) {
591     if (strcmp(func_name, fn->name)==0)
592       RETURN(fn->addr);
593     fn++;
594   }
595   for(i=0; i<_num_picds; i++) {
596     suffix_length = strlen(_picds[i].extension_suffix);
597     if( suffix_length > strlen(func_name) )
598       continue;
599     if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
600       RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
601   }
602   RETURN(return_value);
603 }
604 hidden_alias(clGetExtensionFunctionAddress);
605
606 CL_API_ENTRY cl_int CL_API_CALL
607 clGetPlatformIDs(cl_uint          num_entries,
608                  cl_platform_id * platforms,
609                  cl_uint *        num_platforms) CL_API_SUFFIX__VERSION_1_0 {
610   debug_trace();
611   _initClIcd();
612   if( platforms == NULL && num_platforms == NULL )
613     RETURN(CL_INVALID_VALUE);
614   if( num_entries == 0 && platforms != NULL )
615     RETURN(CL_INVALID_VALUE);
616   if( _num_icds == 0)
617     RETURN(CL_PLATFORM_NOT_FOUND_KHR);
618
619   cl_uint i;
620   if( num_platforms != NULL ){
621     *num_platforms = _num_picds;
622   }
623   if( platforms != NULL ) {
624     cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
625     for( i=0; i<n_platforms; i++) {
626       *(platforms++) = _picds[i].pid;
627     }
628   }
629   return CL_SUCCESS;
630 }
631 hidden_alias(clGetPlatformIDs);
632
633 CL_API_ENTRY cl_context CL_API_CALL
634 clCreateContext(const cl_context_properties *  properties ,
635                 cl_uint                        num_devices ,
636                 const cl_device_id *           devices ,
637                 void (CL_CALLBACK *  pfn_notify )(const char *, const void *, size_t, void *),
638                 void *                         user_data ,
639                 cl_int *                       errcode_ret ){
640   debug_trace();
641   _initClIcd();
642   cl_uint i=0;
643   if( properties != NULL){
644     while( properties[i] != 0 ) {
645       if( properties[i] == CL_CONTEXT_PLATFORM )
646         RETURN(((struct _cl_platform_id *) properties[i+1])
647           ->dispatch->clCreateContext(properties, num_devices, devices,
648                         pfn_notify, user_data, errcode_ret));
649       i += 2;
650     }
651   }
652   if(devices == NULL || num_devices == 0) {
653     if(errcode_ret) {
654       *errcode_ret = CL_INVALID_VALUE;
655     }
656     RETURN(NULL);
657   }
658   RETURN(((struct _cl_device_id *)devices[0])
659     ->dispatch->clCreateContext(properties, num_devices, devices,
660                   pfn_notify, user_data, errcode_ret));
661 }
662 hidden_alias(clCreateContext);
663
664 CL_API_ENTRY cl_context CL_API_CALL
665 clCreateContextFromType(const cl_context_properties *  properties ,
666                         cl_device_type                 device_type ,
667                         void (CL_CALLBACK *      pfn_notify )(const char *, const void *, size_t, void *),
668                         void *                         user_data ,
669                         cl_int *                       errcode_ret ){
670   debug_trace();
671   _initClIcd();
672   cl_uint i=0;
673   if( properties != NULL){
674     while( properties[i] != 0 ) {
675       if( properties[i] == CL_CONTEXT_PLATFORM )
676         if (properties[i+1] == 0) {
677           goto out;
678         }
679         return ((struct _cl_platform_id *) properties[i+1])
680           ->dispatch->clCreateContextFromType(properties, device_type,
681                         pfn_notify, user_data, errcode_ret);
682       i += 2;
683     }
684   } else {
685     /* if properties is null, the selected platform is implementation dependant
686      * We will use the first one if any
687      */
688     if(_num_picds == 0) {
689       if(errcode_ret) {
690         *errcode_ret = CL_INVALID_VALUE;
691       }
692       RETURN(NULL);
693     }
694     RETURN(_picds[0].pid->dispatch->clCreateContextFromType
695         (properties, device_type, pfn_notify, user_data, errcode_ret));
696   }
697  out:
698   if(errcode_ret) {
699     *errcode_ret = CL_INVALID_PLATFORM;
700   }
701   RETURN(NULL);
702 }
703 hidden_alias(clCreateContextFromType);
704
705 CL_API_ENTRY cl_int CL_API_CALL
706 clGetGLContextInfoKHR(const cl_context_properties *  properties ,
707                       cl_gl_context_info             param_name ,
708                       size_t                         param_value_size ,
709                       void *                         param_value ,
710                       size_t *                       param_value_size_ret ){
711   debug_trace();
712   _initClIcd();
713   cl_uint i=0;
714   if( properties != NULL){
715     while( properties[i] != 0 ) {
716       if( properties[i] == CL_CONTEXT_PLATFORM )
717         RETURN(((struct _cl_platform_id *) properties[i+1])
718           ->dispatch->clGetGLContextInfoKHR(properties, param_name,
719                         param_value_size, param_value, param_value_size_ret));
720       i += 2;
721     }
722   }
723   RETURN(CL_INVALID_PLATFORM);
724 }
725 hidden_alias(clGetGLContextInfoKHR);
726
727 CL_API_ENTRY cl_int CL_API_CALL
728 clWaitForEvents(cl_uint              num_events ,
729                 const cl_event *     event_list ){
730   debug_trace();
731   if( num_events == 0 || event_list == NULL )
732     RETURN(CL_INVALID_VALUE);
733   RETURN(((struct _cl_event *)event_list[0])
734     ->dispatch->clWaitForEvents(num_events, event_list));
735 }
736 hidden_alias(clWaitForEvents);
737
738 CL_API_ENTRY cl_int CL_API_CALL
739 clUnloadCompiler( void ){
740   debug_trace();
741   RETURN(CL_SUCCESS);
742 }
743 hidden_alias(clUnloadCompiler);