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