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