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