Skip to content

Commit 1fbecb1

Browse files
Kerilkbashbaug
andcommitted
Deinitialization support.
Co-authored-by: Ben Ashbaugh <ben.ashbaugh@intel.com>
1 parent 634ef47 commit 1fbecb1

File tree

14 files changed

+544
-65
lines changed

14 files changed

+544
-65
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ set (OPENCL_COMPILE_DEFINITIONS
161161
CL_NO_NON_ICD_DISPATCH_EXTENSION_PROTOTYPES
162162
OPENCL_ICD_LOADER_VERSION_MAJOR=3
163163
OPENCL_ICD_LOADER_VERSION_MINOR=0
164-
OPENCL_ICD_LOADER_VERSION_REV=7
164+
OPENCL_ICD_LOADER_VERSION_REV=8
165165
$<$<BOOL:${ENABLE_OPENCL_LAYERS}>:CL_ENABLE_LAYERS>
166166
$<$<BOOL:${ENABLE_OPENCL_LOADER_MANAGED_DISPATCH}>:CL_ENABLE_LOADER_MANAGED_DISPATCH>
167167
)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,5 @@ The following debug environment variables are available for use with the OpenCL
145145
| OPENCL_LAYERS | Specifies a list of layers to load. | `export OPENCL_LAYERS=libLayerA.so:libLayerB.so`<br/><br/>`set OPENCL_LAYERS=libLayerA.dll;libLayerB.dll` |
146146
| OPENCL_LAYER_PATH | On Linux and Android, specifies a directory to scan for layers to enumerate in place of the default `/etc/OpenCL/layers'. | `export OPENCL_LAYER_PATH=/my/local/layers/search/path` |
147147
| OCL_ICD_ENABLE_TRACE | Enable the trace mechanism | `export OCL_ICD_ENABLE_TRACE=True`<br/><br/>`set OCL_ICD_ENABLE_TRACE=True`<br/>`true, T, 1 can also be used here.` |
148+
| OCL_ICD_FORCE_LEGACY_TERMINATION | Forces using the legacy termination scheme. Legacy termination supports older layers, but does not support layer de-initialization and does not close library handles for layers or ICDs. | `export OCL_ICD_FORCE_LEGACY_TERMINATION=True`<br/><br/>`set OCL_ICD_FORCE_LEGACY_TERMINATION=True`<br/>`true, T, 1 can also be used here.` |
149+
| OCL_ICD_DISABLE_DYNAMIC_LIBRARY_UNLOADING | Prevents the ICD loader from closing dynamic library handles for layers and ICDs. This can be used for debugging purposes or to allow leak sanitizers to have full stack traces. | `export OCL_ICD_DISABLE_DYNAMIC_LIBRARY_UNLOADING=True`<br/><br/>`set OCL_ICD_DISABLE_DYNAMIC_LIBRARY_UNLOADING=True`<br/>`true, T, 1 can also be used here.` |

include/cl_khr_icd2.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,31 @@
1818

1919
#include <CL/cl.h>
2020

21+
#if !defined(CL_PLATFORM_UNLOADABLE_KHR)
22+
#define CL_PLATFORM_UNLOADABLE_KHR 0x0921
23+
#endif
24+
25+
#if defined(CL_ENABLE_LAYERS) && !defined(CL_LAYER_PROPERTIES_LIST_END)
26+
typedef cl_properties cl_layer_properties;
27+
28+
#define CL_LAYER_PROPERTIES_LIST_END ((cl_layer_properties)0)
29+
30+
typedef cl_int CL_API_CALL
31+
clInitLayerWithProperties_t(
32+
cl_uint num_entries,
33+
const cl_icd_dispatch *target_dispatch,
34+
cl_uint *num_entries_ret,
35+
const cl_icd_dispatch **layer_dispatch_ret,
36+
const cl_layer_properties *properties);
37+
38+
typedef clInitLayerWithProperties_t *pfn_clInitLayerWithProperties;
39+
40+
typedef cl_int CL_API_CALL
41+
clDeinitLayer_t(void);
42+
43+
typedef clDeinitLayer_t *pfn_clDeinitLayer;
44+
#endif //defined(CL_ENABLE_LAYERS) && !defined(CL_LAYER_PROPERTIES_LIST_END)
45+
2146
#if !defined(CL_ICD2_TAG_KHR)
2247
#if INTPTR_MAX == INT32_MAX
2348
#define CL_ICD2_TAG_KHR ((intptr_t)0x434C3331)

loader/cllayerinfo.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "icd.h"
2020
#include <stdio.h>
2121
#include <stdlib.h>
22-
#include <CL/cl_layer.h>
2322
#if defined(_WIN32)
2423
#include <io.h>
2524
#include <share.h>
@@ -90,7 +89,7 @@ static void restore_outputs(void)
9089
void printLayerInfo(const struct KHRLayer *layer)
9190
{
9291
cl_layer_api_version api_version = 0;
93-
pfn_clGetLayerInfo p_clGetLayerInfo = (pfn_clGetLayerInfo)(size_t)layer->p_clGetLayerInfo;
92+
pfn_clGetLayerInfo p_clGetLayerInfo = layer->p_clGetLayerInfo;
9493
cl_int result = CL_SUCCESS;
9594
size_t sz;
9695

@@ -113,20 +112,26 @@ void printLayerInfo(const struct KHRLayer *layer)
113112
}
114113
}
115114

116-
int main (int argc, char *argv[])
115+
static void run_silently(void (*pfn)(void))
117116
{
118-
(void)argc;
119-
(void)argv;
120117
silence_layers();
121118
atexit(restore_outputs);
122-
khrIcdInitialize();
119+
pfn();
123120
restore_outputs();
124121
atexit(silence_layers);
122+
}
123+
124+
int main (int argc, char *argv[])
125+
{
126+
(void)argc;
127+
(void)argv;
128+
run_silently(&khrIcdInitialize);
125129
const struct KHRLayer *layer = khrFirstLayer;
126130
while (layer)
127131
{
128132
printLayerInfo(layer);
129133
layer = layer->next;
130134
}
135+
run_silently(&khrIcdDeinitialize);
131136
return 0;
132137
}

loader/icd.c

Lines changed: 132 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,48 @@
1919
#include "icd.h"
2020
#include "icd_dispatch.h"
2121
#include "icd_envvars.h"
22-
#if defined(CL_ENABLE_LAYERS)
23-
#include <CL/cl_layer.h>
24-
#endif // defined(CL_ENABLE_LAYERS)
2522
#include <stdlib.h>
2623
#include <string.h>
2724

2825
KHRicdVendor *khrIcdVendors = NULL;
26+
static KHRicdVendor *lastVendor = NULL;
2927
int khrEnableTrace = 0;
28+
static int khrDisableLibraryUnloading = 0;
29+
static int khrForceLegacyTermination = 0;
3030

3131
#if defined(CL_ENABLE_LAYERS)
3232
struct KHRLayer *khrFirstLayer = NULL;
3333
#endif // defined(CL_ENABLE_LAYERS)
3434

35-
// entrypoint to check and initialize trace.
36-
void khrIcdInitializeTrace(void)
35+
static inline int khrIcdCheckEnvTrue(const char *variable)
36+
{
37+
return (variable && (strcmp(variable, "True") == 0 ||
38+
strcmp(variable, "true") == 0 ||
39+
strcmp(variable, "T") == 0 ||
40+
strcmp(variable, "1") == 0));
41+
}
42+
43+
// Set a given flag if the given environement variable is true
44+
static void khrInitializeFlagWithEnv(int *flag, const char *variable)
3745
{
38-
char *enableTrace = khrIcd_getenv("OCL_ICD_ENABLE_TRACE");
39-
if (enableTrace && (strcmp(enableTrace, "True") == 0 ||
40-
strcmp(enableTrace, "true") == 0 ||
41-
strcmp(enableTrace, "T") == 0 ||
42-
strcmp(enableTrace, "1") == 0))
46+
char *variableStr = khrIcd_getenv(variable);
47+
if (khrIcdCheckEnvTrue(variableStr))
48+
{
49+
*flag = 1;
50+
}
51+
if (variableStr)
4352
{
44-
khrEnableTrace = 1;
53+
khrIcd_free_getenv(variableStr);
4554
}
4655
}
4756

57+
void khrIcdInitializeEnvOptions(void)
58+
{
59+
khrInitializeFlagWithEnv(&khrEnableTrace, "OCL_ICD_ENABLE_TRACE");
60+
khrInitializeFlagWithEnv(&khrDisableLibraryUnloading, "OCL_ICD_DISABLE_DYNAMIC_LIBRARY_UNLOADING");
61+
khrInitializeFlagWithEnv(&khrForceLegacyTermination, "OCL_ICD_FORCE_LEGACY_TERMINATION");
62+
}
63+
4864
// entrypoint to initialize the ICD and add all vendors
4965
void khrIcdInitialize(void)
5066
{
@@ -186,6 +202,14 @@ void khrIcdVendorAdd(const char *libraryName)
186202
#endif
187203

188204
// call clGetPlatformInfo on the returned platform to get the suffix
205+
206+
KHR_ICD2_DISPATCH(platforms[i])->clGetPlatformInfo(
207+
platforms[i],
208+
CL_PLATFORM_UNLOADABLE_KHR,
209+
sizeof(vendor->unloadable),
210+
&vendor->unloadable,
211+
NULL);
212+
189213
result = KHR_ICD2_DISPATCH(platforms[i])->clGetPlatformInfo(
190214
platforms[i],
191215
CL_PLATFORM_ICD_SUFFIX_KHR,
@@ -230,11 +254,13 @@ void khrIcdVendorAdd(const char *libraryName)
230254
vendor->suffix = suffix;
231255

232256
// add this vendor to the list of vendors at the tail
233-
{
234-
KHRicdVendor **prevNextPointer = NULL;
235-
for (prevNextPointer = &khrIcdVendors; *prevNextPointer; prevNextPointer = &( (*prevNextPointer)->next) );
236-
*prevNextPointer = vendor;
257+
if (lastVendor) {
258+
lastVendor->next = vendor;
259+
vendor->prev = lastVendor;
260+
} else {
261+
khrIcdVendors = vendor;
237262
}
263+
lastVendor = vendor;
238264

239265
KHR_ICD_TRACE("successfully added vendor %s with suffix %s\n", libraryName, suffix);
240266

@@ -259,6 +285,8 @@ void khrIcdLayerAdd(const char *libraryName)
259285
cl_int result = CL_SUCCESS;
260286
pfn_clGetLayerInfo p_clGetLayerInfo = NULL;
261287
pfn_clInitLayer p_clInitLayer = NULL;
288+
pfn_clInitLayerWithProperties p_clInitLayerWithProperties = NULL;
289+
pfn_clDeinitLayer p_clDeinitLayer = NULL;
262290
struct KHRLayer *layerIterator = NULL;
263291
struct KHRLayer *layer = NULL;
264292
cl_layer_api_version api_version = 0;
@@ -300,14 +328,6 @@ void khrIcdLayerAdd(const char *libraryName)
300328
goto Done;
301329
}
302330

303-
// use that function to get the clInitLayer function pointer
304-
p_clInitLayer = (pfn_clInitLayer)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clInitLayer");
305-
if (!p_clInitLayer)
306-
{
307-
KHR_ICD_TRACE("failed to get function address clInitLayer\n");
308-
goto Done;
309-
}
310-
311331
result = p_clGetLayerInfo(CL_LAYER_API_VERSION, sizeof(api_version), &api_version, NULL);
312332
if (CL_SUCCESS != result)
313333
{
@@ -321,6 +341,31 @@ void khrIcdLayerAdd(const char *libraryName)
321341
goto Done;
322342
}
323343

344+
// Support old version of layers, which should rely on at_exit for termination.
345+
// In this case use clInitLayer to initialize layers
346+
if (khrForceLegacyTermination)
347+
{
348+
p_clInitLayer = (pfn_clInitLayer)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clInitLayer");
349+
if (!p_clInitLayer)
350+
{
351+
KHR_ICD_TRACE("failed to get function address clInitLayer\n");
352+
goto Done;
353+
}
354+
} else { // New scheme, relies on clInitLayerWithProperties and the optional clDeinitLayer for termination
355+
p_clInitLayerWithProperties = (pfn_clInitLayerWithProperties)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clInitLayerWithProperties");
356+
if (!p_clInitLayerWithProperties)
357+
{
358+
KHR_ICD_TRACE("failed to get function address clInitLayerWithProperties\n");
359+
goto Done;
360+
}
361+
362+
p_clDeinitLayer = (pfn_clDeinitLayer)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clDeinitLayer");
363+
if (!p_clDeinitLayer)
364+
{
365+
KHR_ICD_TRACE("layer does not support clDeinitLayer\n");
366+
}
367+
}
368+
324369
layer = (struct KHRLayer*)calloc(sizeof(struct KHRLayer), 1);
325370
if (!layer)
326371
{
@@ -338,9 +383,10 @@ void khrIcdLayerAdd(const char *libraryName)
338383
goto Done;
339384
}
340385
memcpy(layer->libraryName, libraryName, sz_name);
341-
layer->p_clGetLayerInfo = (void *)(size_t)p_clGetLayerInfo;
386+
layer->p_clGetLayerInfo = p_clGetLayerInfo;
342387
}
343388
#endif
389+
layer->p_clDeinitLayer = p_clDeinitLayer;
344390

345391
if (khrFirstLayer) {
346392
targetDispatch = &(khrFirstLayer->dispatch);
@@ -349,11 +395,21 @@ void khrIcdLayerAdd(const char *libraryName)
349395
}
350396

351397
loaderDispatchNumEntries = sizeof(khrMainDispatch)/sizeof(void*);
352-
result = p_clInitLayer(
353-
loaderDispatchNumEntries,
354-
targetDispatch,
355-
&layerDispatchNumEntries,
356-
&layerDispatch);
398+
if (khrForceLegacyTermination)
399+
{
400+
result = p_clInitLayer(
401+
loaderDispatchNumEntries,
402+
targetDispatch,
403+
&layerDispatchNumEntries,
404+
&layerDispatch);
405+
} else {
406+
result = p_clInitLayerWithProperties(
407+
loaderDispatchNumEntries,
408+
targetDispatch,
409+
&layerDispatchNumEntries,
410+
&layerDispatch,
411+
NULL);
412+
}
357413
if (CL_SUCCESS != result)
358414
{
359415
KHR_ICD_TRACE("failed to initialize layer\n");
@@ -472,3 +528,50 @@ void khrIcdContextPropertiesGetPlatform(const cl_context_properties *properties,
472528
}
473529
}
474530

531+
#if defined(CL_ENABLE_LAYERS)
532+
static struct KHRLayer deinitLayer = {0};
533+
#endif
534+
535+
void khrIcdDeinitialize(void) {
536+
if (khrForceLegacyTermination)
537+
{
538+
KHR_ICD_TRACE("ICD Loader deinitialization disabled\n");
539+
return;
540+
}
541+
542+
KHR_ICD_TRACE("ICD Loader deinitialization\n");
543+
544+
#if defined(CL_ENABLE_LAYERS)
545+
// free layers first in reverse order of their creation (front to back)
546+
// they may still need to use vendors while terminating
547+
KHR_ICD_TRACE("Finalizing and unloading layers\n");
548+
struct KHRLayer *head = khrFirstLayer;
549+
deinitLayer.dispatch = khrDeinitDispatch;
550+
khrFirstLayer = &deinitLayer;
551+
552+
while(head) {
553+
struct KHRLayer *cur = head;
554+
#ifdef CL_LAYER_INFO
555+
free(cur->libraryName);
556+
#endif
557+
if (cur->p_clDeinitLayer)
558+
cur->p_clDeinitLayer();
559+
if (!khrDisableLibraryUnloading)
560+
khrIcdOsLibraryUnload(cur->library);
561+
head = cur->next;
562+
free(cur);
563+
}
564+
#endif // defined(CL_ENABLE_LAYERS)
565+
566+
// free vendor in reverse order of their creation (back to front)
567+
KHR_ICD_TRACE("Finalizing and unloading vendors\n");
568+
while (lastVendor) {
569+
KHRicdVendor *cur = lastVendor;
570+
free(cur->suffix);
571+
if (cur->unloadable && !khrDisableLibraryUnloading)
572+
khrIcdOsLibraryUnload(cur->library);
573+
lastVendor = cur->prev;
574+
free(cur);
575+
}
576+
khrIcdVendors = NULL;
577+
}

loader/icd.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
#include <CL/cl.h>
5050
#include <CL/cl_ext.h>
5151
#include <CL/cl_icd.h>
52+
#if defined(CL_ENABLE_LAYERS)
53+
#include <CL/cl_layer.h>
54+
#endif // defined(CL_ENABLE_LAYERS)
5255
#include <stdio.h>
5356

5457
/*
@@ -85,6 +88,9 @@ struct KHRicdVendorRec
8588
// the extension suffix for this platform
8689
char *suffix;
8790

91+
// can this vendor library be unloaded?
92+
cl_bool unloadable;
93+
8894
// function pointer to the ICD platform IDs extracted from the library
8995
pfn_clGetExtensionFunctionAddress clGetExtensionFunctionAddress;
9096

@@ -98,6 +104,7 @@ struct KHRicdVendorRec
98104

99105
// next vendor in the list vendors
100106
KHRicdVendor *next;
107+
KHRicdVendor *prev;
101108
};
102109

103110
// the global state
@@ -123,14 +130,17 @@ struct KHRLayer
123130
#ifdef CL_LAYER_INFO
124131
// The layer library name
125132
char *libraryName;
126-
// the pointer to the clGetLayerInfo funciton
127-
void *p_clGetLayerInfo;
133+
// the pointer to the clGetLayerInfo function
134+
pfn_clGetLayerInfo p_clGetLayerInfo;
128135
#endif
136+
// the pointer to the clDeinitLayer function
137+
pfn_clDeinitLayer p_clDeinitLayer;
129138
};
130139

131140
// the global layer state
132141
extern struct KHRLayer * khrFirstLayer;
133142
extern const struct _cl_icd_dispatch khrMainDispatch;
143+
extern const struct _cl_icd_dispatch khrDeinitDispatch;
134144
#endif // defined(CL_ENABLE_LAYERS)
135145

136146
/*
@@ -144,8 +154,11 @@ extern const struct _cl_icd_dispatch khrMainDispatch;
144154
// API (e.g, getPlatformIDs, etc).
145155
void khrIcdInitialize(void);
146156

147-
// entrypoint to check and initialize trace.
148-
void khrIcdInitializeTrace(void);
157+
// entrypoint to check and initialize env options.
158+
void khrIcdInitializeEnvOptions(void);
159+
160+
// entrypoint to release icd resources
161+
void khrIcdDeinitialize(void);
149162

150163
// go through the list of vendors (in /etc/OpenCL.conf or through
151164
// the registry) and call khrIcdVendorAdd for each vendor encountered

0 commit comments

Comments
 (0)