Fix bug for dumping the internal ICD structure
[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 #ifdef 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 #ifdef 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 #ifdef 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       char *param_value=NULL;
377       p->extension_suffix=NULL;
378       p->vicd=&_icds[i];
379       p->pid=platforms[j];
380 #ifdef DEBUG_OCL_ICD
381       if (debug_ocl_icd_mask & D_DUMP) {
382         int log=debug_ocl_icd_mask & D_TRACE;
383         debug_ocl_icd_mask &= ~D_TRACE;
384         dump_platform(p->vicd->ext_fn_ptr, p->pid);
385         debug_ocl_icd_mask |= log;
386       }
387 #endif
388       {
389               /* Allow to workaround a bug in the Intel ICD used
390                * with optirun (search for NVidia Optimus for more info)
391                */
392               const char* str=getenv("OCL_ICD_ASSUME_ICD_EXTENSION");
393               if (! str || str[0]==0) {
394                       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
395                       if (param_value == NULL){
396                               debug(D_WARN, "Skipping platform %i", j);
397                               continue;
398                       }
399                       debug(D_DUMP, "Supported extensions: %s", param_value);
400                       if( strstr(param_value, "cl_khr_icd") == NULL){
401                               free(param_value); 
402                               debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
403                               continue;
404                       }
405                       free(param_value);
406               }
407       }
408       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
409       if (param_value == NULL){
410         debug(D_WARN, "Skipping platform %i", j);
411         continue;
412       }
413       p->extension_suffix = param_value;
414       debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
415 #ifdef DEBUG_OCL_ICD
416       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
417       if (param_value != NULL){
418         debug(D_DUMP, "Profile: %s", param_value);
419         free(param_value);
420       }
421       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
422       p->version = param_value;
423       if (param_value != NULL){
424         debug(D_DUMP, "Version: %s", param_value);
425         free(param_value);
426       }
427       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
428       if (param_value != NULL){
429         debug(D_DUMP, "Name: %s", param_value);
430         free(param_value);
431       }
432       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
433       if (param_value != NULL){
434         debug(D_DUMP, "Vendor: %s", param_value);
435         free(param_value);
436       }
437 #endif
438       num_valid_platforms++;
439       _num_picds++;
440     }
441     if( num_valid_platforms != 0 ) {
442       if ( _num_icds != i ) {
443         picd->dl_handle = dlh;
444       }
445       _num_icds++;
446       picd->num_platforms = num_valid_platforms;
447       _icds[i].first_platform = _num_picds - num_valid_platforms;
448     } else {
449       dlclose(dlh);
450     }
451     free(platforms);
452   }
453 }
454
455 static void __initClIcd( void ) {
456   debug_init();
457   cl_uint num_icds = 0;
458   int is_dir = 0;
459   DIR *dir;
460   const char* dir_path=getenv("OCL_ICD_VENDORS");
461   if (! dir_path || dir_path[0]==0) {
462     debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
463     dir_path=ETC_OPENCL_VENDORS;
464     is_dir=1;
465   }
466   if (!is_dir) {
467     struct stat buf;
468     int ret=stat(dir_path, &buf);
469     if (ret != 0 && errno != ENOENT) {
470       debug(D_WARN, "Cannot stat '%s'. Aborting", dir_path);
471     }
472     if (ret == 0 && S_ISDIR(buf.st_mode)) {
473       is_dir=1;
474     }
475   }
476   
477   if (!is_dir) {
478     debug(D_LOG,"Only loading '%s' as an ICD", dir_path);
479     num_icds = 1;
480     dir=NULL;
481   } else {
482     debug(D_LOG,"Reading icd list from '%s'", dir_path);
483     dir = opendir(dir_path);
484     if(dir == NULL) {
485       if (errno == ENOTDIR) {
486         debug(D_DUMP, "%s is not a directory, trying to use it as a ICD libname",
487         dir_path);
488       }
489       goto abort;
490     }
491
492     num_icds = _find_num_icds(dir);
493     if(num_icds == 0) {
494       goto abort;
495     }
496   }
497
498   _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
499   if (_icds == NULL) {
500     goto abort;
501   }
502   
503   if (!is_dir) {
504     if (_string_end_with_icd(dir_path)) {
505       num_icds = 0;
506       if (! _string_with_slash(dir_path)) {
507         num_icds = _open_driver(0, ETC_OPENCL_VENDORS, dir_path);
508       }
509       if (num_icds == 0) {
510         num_icds = _open_driver(0, NULL, dir_path);
511       }
512     } else {
513       num_icds = _load_icd(0, dir_path);
514     }
515   } else {
516     num_icds = _open_drivers(dir, dir_path);
517   }
518   if(num_icds == 0) {
519     goto abort;
520   }
521
522   _find_and_check_platforms(num_icds);
523   if(_num_icds == 0){
524     goto abort;
525   }
526
527   if (_num_icds < num_icds) {
528     _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
529   }
530   debug(D_WARN, "%d valid vendor(s)!", _num_icds);
531   return;
532  abort:
533   _num_icds = 0;
534   if (_icds) {
535     free(_icds);
536     _icds = NULL;
537   }
538   return;
539 }
540
541 #ifdef USE_PTHREAD
542 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
543 #else
544 static int gard=0;
545 #endif
546 volatile static __thread int in_init = 0;
547 volatile static cl_uint _initialized = 0;
548
549 static inline void __attribute__((constructor)) _initClIcd( void ) {
550   if( _initialized )
551     return;
552 #ifdef USE_PTHREAD
553   if (in_init) {
554     /* probably reentrency */
555   } else {
556     in_init=1;
557     __sync_synchronize();
558     pthread_once(&once_init, &__initClIcd);
559     __sync_synchronize();
560     in_init=0;
561   }
562 #else
563   if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
564     in_init=1;
565     __sync_synchronize();
566     __initClIcd();
567     __sync_synchronize();
568     in_init=0;
569   } else {
570     if (in_init) {
571       /* probably reentrency (could also be user threads). */
572     } else {
573       /* someone else started __initClIcd(). We wait until its end. */
574       debug(D_WARN, "Waiting end of init");
575       while (!_initialized) ;
576       debug(D_WARN, "Wait done");
577    }
578   }
579 #endif
580   _initialized = 1;
581 }
582
583 #pragma GCC visibility pop
584 #define hidden_alias(name) \
585   typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
586
587 CL_API_ENTRY void * CL_API_CALL
588 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
589   debug_trace();
590   _initClIcd();
591   if( func_name == NULL )
592     return NULL;
593   cl_uint suffix_length;
594   cl_uint i;
595   void * return_value=NULL;
596   struct func_desc const * fn=&function_description[0];
597   while (fn->name != NULL) {
598     if (strcmp(func_name, fn->name)==0)
599       RETURN(fn->addr);
600     fn++;
601   }
602   for(i=0; i<_num_picds; i++) {
603     suffix_length = strlen(_picds[i].extension_suffix);
604     if( suffix_length > strlen(func_name) )
605       continue;
606     if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
607       RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
608   }
609   RETURN(return_value);
610 }
611 hidden_alias(clGetExtensionFunctionAddress);
612
613 CL_API_ENTRY cl_int CL_API_CALL
614 clGetPlatformIDs(cl_uint          num_entries,
615                  cl_platform_id * platforms,
616                  cl_uint *        num_platforms) CL_API_SUFFIX__VERSION_1_0 {
617   debug_trace();
618   _initClIcd();
619   if( platforms == NULL && num_platforms == NULL )
620     RETURN(CL_INVALID_VALUE);
621   if( num_entries == 0 && platforms != NULL )
622     RETURN(CL_INVALID_VALUE);
623   if( _num_icds == 0)
624     RETURN(CL_PLATFORM_NOT_FOUND_KHR);
625
626   cl_uint i;
627   if( num_platforms != NULL ){
628     *num_platforms = _num_picds;
629   }
630   if( platforms != NULL ) {
631     cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
632     for( i=0; i<n_platforms; i++) {
633       *(platforms++) = _picds[i].pid;
634     }
635   }
636   return CL_SUCCESS;
637 }
638 hidden_alias(clGetPlatformIDs);
639
640 CL_API_ENTRY cl_context CL_API_CALL
641 clCreateContext(const cl_context_properties *  properties ,
642                 cl_uint                        num_devices ,
643                 const cl_device_id *           devices ,
644                 void (CL_CALLBACK *  pfn_notify )(const char *, const void *, size_t, void *),
645                 void *                         user_data ,
646                 cl_int *                       errcode_ret ){
647   debug_trace();
648   _initClIcd();
649   cl_uint i=0;
650   if( properties != NULL){
651     while( properties[i] != 0 ) {
652       if( properties[i] == CL_CONTEXT_PLATFORM )
653         RETURN(((struct _cl_platform_id *) properties[i+1])
654           ->dispatch->clCreateContext(properties, num_devices, devices,
655                         pfn_notify, user_data, errcode_ret));
656       i += 2;
657     }
658   }
659   if(devices == NULL || num_devices == 0) {
660     if(errcode_ret) {
661       *errcode_ret = CL_INVALID_VALUE;
662     }
663     RETURN(NULL);
664   }
665   RETURN(((struct _cl_device_id *)devices[0])
666     ->dispatch->clCreateContext(properties, num_devices, devices,
667                   pfn_notify, user_data, errcode_ret));
668 }
669 hidden_alias(clCreateContext);
670
671 CL_API_ENTRY cl_context CL_API_CALL
672 clCreateContextFromType(const cl_context_properties *  properties ,
673                         cl_device_type                 device_type ,
674                         void (CL_CALLBACK *      pfn_notify )(const char *, const void *, size_t, void *),
675                         void *                         user_data ,
676                         cl_int *                       errcode_ret ){
677   debug_trace();
678   _initClIcd();
679   cl_uint i=0;
680   if( properties != NULL){
681     while( properties[i] != 0 ) {
682       if( properties[i] == CL_CONTEXT_PLATFORM )
683         if (properties[i+1] == 0) {
684           goto out;
685         }
686         return ((struct _cl_platform_id *) properties[i+1])
687           ->dispatch->clCreateContextFromType(properties, device_type,
688                         pfn_notify, user_data, errcode_ret);
689       i += 2;
690     }
691   } else {
692     /* if properties is null, the selected platform is implementation dependant
693      * We will use the first one if any
694      */
695     if(_num_picds == 0) {
696       if(errcode_ret) {
697         *errcode_ret = CL_INVALID_VALUE;
698       }
699       RETURN(NULL);
700     }
701     RETURN(_picds[0].pid->dispatch->clCreateContextFromType
702         (properties, device_type, pfn_notify, user_data, errcode_ret));
703   }
704  out:
705   if(errcode_ret) {
706     *errcode_ret = CL_INVALID_PLATFORM;
707   }
708   RETURN(NULL);
709 }
710 hidden_alias(clCreateContextFromType);
711
712 CL_API_ENTRY cl_int CL_API_CALL
713 clGetGLContextInfoKHR(const cl_context_properties *  properties ,
714                       cl_gl_context_info             param_name ,
715                       size_t                         param_value_size ,
716                       void *                         param_value ,
717                       size_t *                       param_value_size_ret ){
718   debug_trace();
719   _initClIcd();
720   cl_uint i=0;
721   if( properties != NULL){
722     while( properties[i] != 0 ) {
723       if( properties[i] == CL_CONTEXT_PLATFORM )
724         RETURN(((struct _cl_platform_id *) properties[i+1])
725           ->dispatch->clGetGLContextInfoKHR(properties, param_name,
726                         param_value_size, param_value, param_value_size_ret));
727       i += 2;
728     }
729   }
730   RETURN(CL_INVALID_PLATFORM);
731 }
732 hidden_alias(clGetGLContextInfoKHR);
733
734 CL_API_ENTRY cl_int CL_API_CALL
735 clWaitForEvents(cl_uint              num_events ,
736                 const cl_event *     event_list ){
737   debug_trace();
738   if( num_events == 0 || event_list == NULL )
739     RETURN(CL_INVALID_VALUE);
740   RETURN(((struct _cl_event *)event_list[0])
741     ->dispatch->clWaitForEvents(num_events, event_list));
742 }
743 hidden_alias(clWaitForEvents);
744
745 CL_API_ENTRY cl_int CL_API_CALL
746 clUnloadCompiler( void ){
747   debug_trace();
748   RETURN(CL_SUCCESS);
749 }
750 hidden_alias(clUnloadCompiler);