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