Allow OCL_ICD_VENDORS to directly provide the ICD library name to load
[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 cl_uint _find_num_icds(DIR *dir) {
170   cl_uint num_icds = 0;
171   struct dirent *ent;
172   while( (ent=readdir(dir)) != NULL ){
173     cl_uint d_name_len = strlen(ent->d_name);
174     if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
175       continue;
176     num_icds++;
177   }
178   rewinddir(dir);
179   RETURN(num_icds);
180 }
181
182 static inline cl_uint _load_icd(int num_icds, const char* lib_path) {
183   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, skipping ICD");
192   }
193   return ret;
194 }
195
196 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
197   cl_uint num_icds = 0;
198   struct dirent *ent;
199   while( (ent=readdir(dir)) != NULL ){
200     cl_uint d_name_len = strlen(ent->d_name);
201     if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
202       continue;
203     char * lib_path;
204     char * err;
205     unsigned int lib_path_length = strlen(dir_path) + strlen(ent->d_name) + 2;
206     lib_path = malloc(lib_path_length*sizeof(char));
207     sprintf(lib_path,"%s/%s", dir_path, ent->d_name);
208     debug(D_LOG, "Considering file '%s'", lib_path);
209     FILE *f = fopen(lib_path,"r");
210     free(lib_path);
211
212     fseek(f, 0, SEEK_END);
213     lib_path_length = ftell(f)+1;
214     fseek(f, 0, SEEK_SET);
215     if(lib_path_length == 1) {
216       debug(D_WARN, "File contents too short, skipping ICD");
217       fclose(f);
218       continue;
219     }
220     lib_path = malloc(lib_path_length*sizeof(char));
221     err = fgets(lib_path, lib_path_length, f);
222     fclose(f);
223     if( err == NULL ) {
224       free(lib_path);
225       debug(D_WARN, "Error while loading file contents, skipping ICD");
226       continue;
227     }
228
229     lib_path_length = strlen(lib_path);
230     
231     if( lib_path[lib_path_length-1] == '\n' )
232       lib_path[lib_path_length-1] = '\0';
233
234     num_icds += _load_icd(num_icds, lib_path);
235
236     free(lib_path);
237   }
238   RETURN(num_icds);
239 }
240
241 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
242   void *addr1;
243   debug(D_LOG,"Looking for function %s",name);
244   addr1=dlsym(dlh, name);
245   if (addr1 == NULL) {
246     debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
247   }
248   void* addr2=NULL;
249   if (fn) {
250     addr2=(*fn)(name);
251     if (addr2 == NULL) {
252       debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
253     }
254 #if DEBUG_OCL_ICD
255     if (addr1 && addr2 && addr1!=addr2) {
256       debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
257     }
258 #endif
259   }
260   if (!addr2) addr2=addr1;
261   RETURN(addr2);
262 }
263
264 static int _allocate_platforms(int req) {
265   static cl_uint allocated=0;
266   debug(D_LOG,"Requesting allocation for %d platforms",req);
267   if (allocated - _num_picds < req) {
268     if (allocated==0) {
269       _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
270     } else {
271       req = req - (allocated - _num_picds);
272       _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
273     }
274     allocated += req;
275   }
276   RETURN(allocated - _num_picds);
277 }
278
279 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
280                  cl_platform_id pid, cl_platform_info cname, char* sname) {
281   cl_int error;
282   size_t param_value_size_ret;
283   error = plt_info_ptr(pid, cname, 0, NULL, &param_value_size_ret);
284   if (error != CL_SUCCESS) {
285     debug(D_WARN, "Error %s while requesting %s in platform %p",
286           _clerror2string(error), sname, pid);
287     return NULL;
288   }
289   char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
290   if (param_value == NULL) {
291     debug(D_WARN, "Error in malloc while requesting %s in platform %p",
292           sname, pid);
293     return NULL;
294   }
295   error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
296   if (error != CL_SUCCESS){
297     free(param_value);
298     debug(D_WARN, "Error %s while requesting %s in platform %p",
299           _clerror2string(error), sname, pid);
300     return NULL;
301   }
302   RETURN_STR(param_value);
303 }
304
305 static inline void _find_and_check_platforms(cl_uint num_icds) {
306   cl_uint i;
307   _num_icds = 0;
308   for( i=0; i<num_icds; i++){
309     debug(D_LOG, "Checking ICD %i", i);
310     struct vendor_icd *picd = &_icds[_num_icds];
311     void* dlh = _icds[i].dl_handle;
312     picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
313     clIcdGetPlatformIDsKHR_fn plt_fn_ptr = 
314       _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
315     clGetPlatformInfo_fn plt_info_ptr = 
316       _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
317     if( picd->ext_fn_ptr == NULL
318         || plt_fn_ptr == NULL
319         || plt_info_ptr == NULL) {
320       debug(D_WARN, "Missing symbols in ICD, skipping it");
321       continue;
322     }
323     cl_uint num_platforms=0;
324     cl_int error;
325     error = (*plt_fn_ptr)(0, NULL, &num_platforms);
326     if( error != CL_SUCCESS || num_platforms == 0) {
327       debug(D_LOG, "No platform in ICD, skipping it");
328       continue;
329     }
330     cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
331     error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
332     if( error != CL_SUCCESS ){
333       free(platforms);
334       debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
335       continue;
336     }
337     cl_uint num_valid_platforms=0;
338     cl_uint j;
339     debug(D_LOG, "Try to load %d plateforms", num_platforms);
340     if (_allocate_platforms(num_platforms) < num_platforms) {
341       free(platforms);
342       debug(D_WARN, "Not enought platform allocated. Skipping ICD");
343       continue;
344     }
345     for(j=0; j<num_platforms; j++) {
346       debug(D_LOG, "Checking platform %i", j);
347       struct platform_icd *p=&_picds[_num_picds];
348       p->extension_suffix=NULL;
349       p->vicd=&_icds[i];
350       p->pid=platforms[j];
351 #if DEBUG_OCL_ICD
352       if (debug_ocl_icd_mask & D_DUMP) {
353         dump_platform(p->vicd->ext_fn_ptr, p->pid);
354       }
355 #endif
356       char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
357       if (param_value == NULL){
358         debug(D_WARN, "Skipping platform %i", j);
359         continue;
360       }
361       debug(D_DUMP, "Supported extensions: %s", param_value);
362       if( strstr(param_value, "cl_khr_icd") == NULL){
363         free(param_value);
364         debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
365         continue;
366       }
367       free(param_value);
368       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
369       if (param_value == NULL){
370         debug(D_WARN, "Skipping platform %i", j);
371         continue;
372       }
373       p->extension_suffix = param_value;
374       debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
375 #if DEBUG_OCL_ICD
376       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
377       if (param_value != NULL){
378         debug(D_DUMP, "Profile: %s", param_value);
379         free(param_value);
380       }
381 #endif
382       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
383       p->version = param_value;
384       if (param_value != NULL){
385         debug(D_DUMP, "Version: %s", param_value);
386         free(param_value);
387       }
388 #if DEBUG_OCL_ICD
389       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
390       if (param_value != NULL){
391         debug(D_DUMP, "Name: %s", param_value);
392         free(param_value);
393       }
394       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
395       if (param_value != NULL){
396         debug(D_DUMP, "Vendor: %s", param_value);
397         free(param_value);
398       }
399 #endif
400       num_valid_platforms++;
401       _num_picds++;
402     }
403     if( num_valid_platforms != 0 ) {
404       if ( _num_icds != i ) {
405         picd->dl_handle = dlh;
406       }
407       _num_icds++;
408       picd->num_platforms = num_valid_platforms;
409       _icds[i].first_platform = _num_picds - num_valid_platforms;
410     } else {
411       dlclose(dlh);
412     }
413     free(platforms);
414   }
415 }
416
417 static void __initClIcd( void ) {
418   debug_init();
419   cl_uint num_icds = 0;
420   int is_dir = 0;
421   DIR *dir;
422   const char* dir_path=getenv("OCL_ICD_VENDORS");
423   if (! dir_path || dir_path[0]==0) {
424     debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
425     dir_path=ETC_OPENCL_VENDORS;
426     is_dir=1;
427   }
428   if (!is_dir) {
429     struct stat buf;
430     int ret=stat(dir_path, &buf);
431     if (ret != 0 && errno != ENOENT) {
432       debug(D_WARN, "Cannot stat '%s'. Aborting", dir_path);
433     }
434     if (ret == 0 && S_ISDIR(buf.st_mode)) {
435       is_dir=1;
436     }
437   }
438   
439   if (!is_dir) {
440     debug(D_LOG,"Only loading '%s' as an ICD", dir_path);
441     num_icds = 1;
442     dir=NULL;
443   } else {
444     debug(D_LOG,"Reading icd list from '%s'", dir_path);
445     dir = opendir(dir_path);
446     if(dir == NULL) {
447       if (errno == ENOTDIR) {
448         debug(D_DUMP, "%s is not a directory, trying to use it as a ICD libname",
449         dir_path);
450       }
451       goto abort;
452     }
453
454     num_icds = _find_num_icds(dir);
455     if(num_icds == 0) {
456       goto abort;
457     }
458   }
459
460   _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
461   if (_icds == NULL) {
462     goto abort;
463   }
464   
465   if (!is_dir) {
466     num_icds = _load_icd(0, dir_path);
467   } else {
468     num_icds = _open_drivers(dir, dir_path);
469   }
470   if(num_icds == 0) {
471     goto abort;
472   }
473
474   _find_and_check_platforms(num_icds);
475   if(_num_icds == 0){
476     goto abort;
477   }
478
479   if (_num_icds < num_icds) {
480     _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
481   }
482   debug(D_WARN, "%d valid vendor(s)!", _num_icds);
483   return;
484  abort:
485   _num_icds = 0;
486   if (_icds) {
487     free(_icds);
488     _icds = NULL;
489   }
490   return;
491 }
492
493 #ifdef USE_PTHREAD
494 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
495 #else
496 static int gard=0;
497 #endif
498 volatile static cl_uint _initialized = 0;
499
500 static inline void __attribute__((constructor)) _initClIcd( void ) {
501   if( _initialized )
502     return;
503 #ifdef USE_PTHREAD
504   pthread_once(&once_init, &__initClIcd);
505 #else
506   if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
507     __initClIcd();
508   } else {
509     /* someone else started __initClIcd(). We wait until its end. */
510     while (!_initialized) ;
511   }
512 #endif
513   _initialized = 1;
514 }
515
516 #pragma GCC visibility pop
517 #define hidden_alias(name) \
518   typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
519
520 CL_API_ENTRY void * CL_API_CALL
521 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
522   debug_trace();
523   _initClIcd();
524   if( func_name == NULL )
525     return NULL;
526   cl_uint suffix_length;
527   cl_uint i;
528   void * return_value=NULL;
529   struct func_desc const * fn=&function_description[0];
530   while (fn->name != NULL) {
531     if (strcmp(func_name, fn->name)==0)
532       RETURN(fn->addr);
533     fn++;
534   }
535   for(i=0; i<_num_picds; i++) {
536     suffix_length = strlen(_picds[i].extension_suffix);
537     if( suffix_length > strlen(func_name) )
538       continue;
539     if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
540       RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
541   }
542   RETURN(return_value);
543 }
544 hidden_alias(clGetExtensionFunctionAddress);
545
546 CL_API_ENTRY cl_int CL_API_CALL
547 clGetPlatformIDs(cl_uint          num_entries,
548                  cl_platform_id * platforms,
549                  cl_uint *        num_platforms) CL_API_SUFFIX__VERSION_1_0 {
550   debug_trace();
551   _initClIcd();
552   if( platforms == NULL && num_platforms == NULL )
553     RETURN(CL_INVALID_VALUE);
554   if( num_entries == 0 && platforms != NULL )
555     RETURN(CL_INVALID_VALUE);
556   if( _num_icds == 0)
557     RETURN(CL_PLATFORM_NOT_FOUND_KHR);
558
559   cl_uint i;
560   if( num_platforms != NULL ){
561     *num_platforms = _num_picds;
562   }
563   if( platforms != NULL ) {
564     cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
565     for( i=0; i<n_platforms; i++) {
566       *(platforms++) = _picds[i].pid;
567     }
568   }
569   return CL_SUCCESS;
570 }
571 hidden_alias(clGetPlatformIDs);
572
573 CL_API_ENTRY cl_context CL_API_CALL
574 clCreateContext(const cl_context_properties *  properties ,
575                 cl_uint                        num_devices ,
576                 const cl_device_id *           devices ,
577                 void (CL_CALLBACK *  pfn_notify )(const char *, const void *, size_t, void *),
578                 void *                         user_data ,
579                 cl_int *                       errcode_ret ){
580   debug_trace();
581   _initClIcd();
582   cl_uint i=0;
583   if( properties != NULL){
584     while( properties[i] != 0 ) {
585       if( properties[i] == CL_CONTEXT_PLATFORM )
586         RETURN(((struct _cl_platform_id *) properties[i+1])
587           ->dispatch->clCreateContext(properties, num_devices, devices,
588                         pfn_notify, user_data, errcode_ret));
589       i += 2;
590     }
591   }
592   if(devices == NULL || num_devices == 0) {
593     if(errcode_ret) {
594       *errcode_ret = CL_INVALID_VALUE;
595     }
596     RETURN(NULL);
597   }
598   RETURN(((struct _cl_device_id *)devices[0])
599     ->dispatch->clCreateContext(properties, num_devices, devices,
600                   pfn_notify, user_data, errcode_ret));
601 }
602 hidden_alias(clCreateContext);
603
604 CL_API_ENTRY cl_context CL_API_CALL
605 clCreateContextFromType(const cl_context_properties *  properties ,
606                         cl_device_type                 device_type ,
607                         void (CL_CALLBACK *      pfn_notify )(const char *, const void *, size_t, void *),
608                         void *                         user_data ,
609                         cl_int *                       errcode_ret ){
610   debug_trace();
611   _initClIcd();
612   cl_uint i=0;
613   if( properties != NULL){
614     while( properties[i] != 0 ) {
615       if( properties[i] == CL_CONTEXT_PLATFORM )
616         if (properties[i+1] == 0) {
617           goto out;
618         }
619         return ((struct _cl_platform_id *) properties[i+1])
620           ->dispatch->clCreateContextFromType(properties, device_type,
621                         pfn_notify, user_data, errcode_ret);
622       i += 2;
623     }
624   } else {
625     /* if properties is null, the selected platform is implementation dependant
626      * We will use the first one if any
627      */
628     if(_num_picds == 0) {
629       if(errcode_ret) {
630         *errcode_ret = CL_INVALID_VALUE;
631       }
632       RETURN(NULL);
633     }
634     RETURN(_picds[0].pid->dispatch->clCreateContextFromType
635         (properties, device_type, pfn_notify, user_data, errcode_ret));
636   }
637  out:
638   if(errcode_ret) {
639     *errcode_ret = CL_INVALID_PLATFORM;
640   }
641   RETURN(NULL);
642 }
643 hidden_alias(clCreateContextFromType);
644
645 CL_API_ENTRY cl_int CL_API_CALL
646 clGetGLContextInfoKHR(const cl_context_properties *  properties ,
647                       cl_gl_context_info             param_name ,
648                       size_t                         param_value_size ,
649                       void *                         param_value ,
650                       size_t *                       param_value_size_ret ){
651   debug_trace();
652   _initClIcd();
653   cl_uint i=0;
654   if( properties != NULL){
655     while( properties[i] != 0 ) {
656       if( properties[i] == CL_CONTEXT_PLATFORM )
657         RETURN(((struct _cl_platform_id *) properties[i+1])
658           ->dispatch->clGetGLContextInfoKHR(properties, param_name,
659                         param_value_size, param_value, param_value_size_ret));
660       i += 2;
661     }
662   }
663   RETURN(CL_INVALID_PLATFORM);
664 }
665 hidden_alias(clGetGLContextInfoKHR);
666
667 CL_API_ENTRY cl_int CL_API_CALL
668 clWaitForEvents(cl_uint              num_events ,
669                 const cl_event *     event_list ){
670   debug_trace();
671   if( num_events == 0 || event_list == NULL )
672     RETURN(CL_INVALID_VALUE);
673   RETURN(((struct _cl_event *)event_list[0])
674     ->dispatch->clWaitForEvents(num_events, event_list));
675 }
676 hidden_alias(clWaitForEvents);
677
678 CL_API_ENTRY cl_int CL_API_CALL
679 clUnloadCompiler( void ){
680   debug_trace();
681   RETURN(CL_SUCCESS);
682 }
683 hidden_alias(clUnloadCompiler);