2727#include <sys/stat.h>
2828#include <dirent.h>
2929#include <pthread.h>
30+ #include <limits.h>
3031
3132static pthread_once_t initialized = PTHREAD_ONCE_INIT ;
3233
@@ -36,112 +37,169 @@ static pthread_once_t initialized = PTHREAD_ONCE_INIT;
3637 *
3738 */
3839
39- // go through the list of vendors in the two configuration files
40- void khrIcdOsVendorsEnumerate (void )
40+ typedef void khrIcdFileAdd (const char * );
41+
42+ static inline void khrIcdOsDirEntryValidateAndAdd (const char * d_name , const char * path ,
43+ const char * extension , khrIcdFileAdd addFunc )
44+ {
45+ struct stat statBuff ;
46+ char * fileName = NULL ;
47+
48+ // make sure the file name ends in `extension` (eg. .icd, or .lay)
49+ if (strlen (extension ) > strlen (d_name ))
50+ {
51+ return ;
52+ }
53+ if (strcmp (d_name + strlen (d_name ) - strlen (extension ), extension ))
54+ {
55+ return ;
56+ }
57+
58+ // allocate space for the full path of the vendor library name
59+ fileName = malloc (strlen (d_name ) + strlen (path ) + 2 );
60+ if (!fileName )
61+ {
62+ KHR_ICD_TRACE ("Failed allocate space for ICD file path\n" );
63+ return ;
64+ }
65+ sprintf (fileName , "%s/%s" , path , d_name );
66+
67+ if (stat (fileName , & statBuff ))
68+ {
69+ KHR_ICD_TRACE ("Failed stat for: %s, continuing\n" , fileName );
70+ free (fileName );
71+ return ;
72+ }
73+
74+ if (S_ISREG (statBuff .st_mode ) || S_ISLNK (statBuff .st_mode ))
75+ {
76+ FILE * fin = NULL ;
77+ char * buffer = NULL ;
78+ long bufferSize = 0 ;
79+
80+ // open the file and read its contents
81+ fin = fopen (fileName , "r" );
82+ if (!fin )
83+ {
84+ free (fileName );
85+ return ;
86+ }
87+ fseek (fin , 0 , SEEK_END );
88+ bufferSize = ftell (fin );
89+
90+ buffer = malloc (bufferSize + 1 );
91+ if (!buffer )
92+ {
93+ free (fileName );
94+ fclose (fin );
95+ return ;
96+ }
97+ memset (buffer , 0 , bufferSize + 1 );
98+ fseek (fin , 0 , SEEK_SET );
99+ if (bufferSize != (long )fread (buffer , 1 , bufferSize , fin ))
100+ {
101+ free (fileName );
102+ free (buffer );
103+ fclose (fin );
104+ return ;
105+ }
106+ // ignore a newline at the end of the file
107+ if (buffer [bufferSize - 1 ] == '\n' ) buffer [bufferSize - 1 ] = '\0' ;
108+
109+ // load the string read from the file
110+ addFunc (buffer );
111+
112+ free (fileName );
113+ free (buffer );
114+ fclose (fin );
115+ }
116+ else
117+ {
118+ KHR_ICD_TRACE ("File %s is not a regular file nor symbolic link, continuing\n" , fileName );
119+ free (fileName );
120+ }
121+ }
122+
123+ struct dirElem
124+ {
125+ char * d_name ;
126+ unsigned char d_type ;
127+ };
128+
129+ static int compareDirElem (const void * a , const void * b )
130+ {
131+ // sort files the same way libc alpahnumerically sorts directory entries.
132+ return strcoll (((struct dirElem * )a )-> d_name , ((struct dirElem * )b )-> d_name );
133+ }
134+
135+ static inline void khrIcdOsDirEnumerate (char * path , char * env , const char * extension ,
136+ khrIcdFileAdd addFunc , int bSort )
41137{
42138 DIR * dir = NULL ;
43- struct dirent * dirEntry = NULL ;
44- const char * vendorPath = ICD_VENDOR_PATH ;
45139 char * envPath = NULL ;
46140
47- khrIcdInitializeTrace ();
48- khrIcdVendorsEnumerateEnv ();
49-
50- envPath = khrIcd_secure_getenv ("OCL_ICD_VENDORS" );
141+ envPath = khrIcd_secure_getenv (env );
51142 if (NULL != envPath )
52143 {
53- vendorPath = envPath ;
144+ path = envPath ;
54145 }
55146
56- dir = opendir (vendorPath );
57- if (NULL == dir )
147+ dir = opendir (path );
148+ if (NULL == dir )
58149 {
59- KHR_ICD_TRACE ("Failed to open path %s, continuing\n" , vendorPath );
150+ KHR_ICD_TRACE ("Failed to open path %s, continuing\n" , path );
60151 }
61152 else
62153 {
63- // attempt to load all files in the directory
64- for (dirEntry = readdir (dir ); dirEntry ; dirEntry = readdir (dir ))
65- {
66- struct stat statBuff ;
67- const char * extension = ".icd" ;
68- char * fileName = NULL ;
69-
70- // make sure the file name ends in .icd
71- if (strlen (extension ) > strlen (dirEntry -> d_name ))
72- {
73- continue ;
74- }
75- if (strcmp (dirEntry -> d_name + strlen (dirEntry -> d_name ) - strlen (extension ), extension ))
76- {
77- continue ;
78- }
154+ struct dirent * dirEntry = NULL ;
79155
80- // allocate space for the full path of the vendor library name
81- fileName = malloc (strlen (dirEntry -> d_name ) + strlen (vendorPath ) + 2 );
82- if (!fileName )
83- {
84- KHR_ICD_TRACE ("Failed allocate space for ICD file path\n" );
85- continue ;
86- }
87- sprintf (fileName , "%s/%s" , vendorPath , dirEntry -> d_name );
156+ // attempt to load all files in the directory
157+ if (bSort ) {
158+ // store the entries name and type in a buffer for sorting
159+ size_t sz = 0 ;
160+ size_t elemCount = 0 ;
161+ size_t elemAlloc = 0 ;
162+ struct dirElem * dirElems = NULL ;
163+ struct dirElem * newDirElems = NULL ;
164+ const size_t startupAlloc = 8 ;
88165
89- if ( stat ( fileName , & statBuff ))
90- {
91- KHR_ICD_TRACE ( "Failed stat for: %s, continuing\n" , fileName );
92- free ( fileName ) ;
93- continue ;
94- }
166+ // start with a small buffer
167+ dirElems = ( struct dirElem * ) malloc ( startupAlloc * sizeof ( struct dirElem ));
168+ if ( NULL != dirElems ) {
169+ elemAlloc = startupAlloc ;
170+ for ( dirEntry = readdir ( dir ); dirEntry ; dirEntry = readdir ( dir ) ) {
171+ char * nameCopy = NULL ;
95172
96- if (S_ISREG (statBuff .st_mode ) || S_ISLNK (statBuff .st_mode ))
97- {
98- FILE * fin = NULL ;
99- char * buffer = NULL ;
100- long bufferSize = 0 ;
101-
102- // open the file and read its contents
103- fin = fopen (fileName , "r" );
104- if (!fin )
105- {
106- free (fileName );
107- continue ;
108- }
109- fseek (fin , 0 , SEEK_END );
110- bufferSize = ftell (fin );
111-
112- buffer = malloc (bufferSize + 1 );
113- if (!buffer )
114- {
115- free (fileName );
116- fclose (fin );
117- continue ;
173+ if (elemCount + 1 > elemAlloc ) {
174+ // double buffer size if necessary and possible
175+ if (elemAlloc >= UINT_MAX /2 )
176+ break ;
177+ newDirElems = (struct dirElem * )realloc (dirElems , elemAlloc * 2 * sizeof (struct dirElem ));
178+ if (NULL == newDirElems )
179+ break ;
180+ dirElems = newDirElems ;
181+ elemAlloc *= 2 ;
182+ }
183+ sz = strlen (dirEntry -> d_name ) + 1 ;
184+ nameCopy = (char * )malloc (sz );
185+ if (NULL == nameCopy )
186+ break ;
187+ memcpy (nameCopy , dirEntry -> d_name , sz );
188+ dirElems [elemCount ].d_name = nameCopy ;
189+ dirElems [elemCount ].d_type = dirEntry -> d_type ;
190+ elemCount ++ ;
118191 }
119- memset (buffer , 0 , bufferSize + 1 );
120- fseek (fin , 0 , SEEK_SET );
121- if (bufferSize != (long )fread (buffer , 1 , bufferSize , fin ))
122- {
123- free (fileName );
124- free (buffer );
125- fclose (fin );
126- continue ;
192+ qsort (dirElems , elemCount , sizeof (struct dirElem ), compareDirElem );
193+ for (struct dirElem * elem = dirElems ; elem < dirElems + elemCount ; ++ elem ) {
194+ khrIcdOsDirEntryValidateAndAdd (elem -> d_name , path , extension , addFunc );
195+ free (elem -> d_name );
127196 }
128- // ignore a newline at the end of the file
129- if (buffer [bufferSize - 1 ] == '\n' ) buffer [bufferSize - 1 ] = '\0' ;
130-
131- // load the string read from the file
132- khrIcdVendorAdd (buffer );
133-
134- free (fileName );
135- free (buffer );
136- fclose (fin );
197+ free (dirElems );
137198 }
138- else
139- {
140- KHR_ICD_TRACE ("File %s is not a regular file nor symbolic link, continuing\n" , fileName );
141- free (fileName );
142- continue ;
143- }
144- }
199+ } else
200+ // use system provided ordering
201+ for (dirEntry = readdir (dir ); dirEntry ; dirEntry = readdir (dir ) )
202+ khrIcdOsDirEntryValidateAndAdd (dirEntry -> d_name , path , extension , addFunc );
145203
146204 closedir (dir );
147205 }
@@ -150,7 +208,20 @@ void khrIcdOsVendorsEnumerate(void)
150208 {
151209 khrIcd_free_getenv (envPath );
152210 }
211+ }
212+
213+ // go through the list of vendors in the two configuration files
214+ void khrIcdOsVendorsEnumerate (void )
215+ {
216+ khrIcdInitializeTrace ();
217+ khrIcdVendorsEnumerateEnv ();
218+
219+ khrIcdOsDirEnumerate (ICD_VENDOR_PATH , "OCL_ICD_VENDORS" , ".icd" , khrIcdVendorAdd , 0 );
220+
153221#if defined(CL_ENABLE_LAYERS )
222+ // system layers should be closer to the driver
223+ khrIcdOsDirEnumerate (LAYER_PATH , "OPENCL_LAYER_PATH" , ".lay" , khrIcdLayerAdd , 1 );
224+
154225 khrIcdLayersEnumerateEnv ();
155226#endif // defined(CL_ENABLE_LAYERS)
156227}
0 commit comments