@@ -319,45 +319,33 @@ cl_int(CL_API_CALL *)(cl_command_buffer_khr command_buffer,
319
319
template <typename T> struct FuncPtrCache {
320
320
std::map<cl_context, T> Map;
321
321
std::mutex Mutex;
322
+
323
+ void clear (cl_context context) {
324
+ std::lock_guard<std::mutex> CacheLock{Mutex};
325
+ Map.erase (context);
326
+ }
322
327
};
323
328
324
- // FIXME: There's currently no mechanism for cleaning up this cache, meaning
325
- // that it is invalidated whenever a context is destroyed. This could lead to
326
- // reusing an invalid function pointer if another context happens to have the
327
- // same native handle.
328
329
struct ExtFuncPtrCacheT {
329
- FuncPtrCache<clHostMemAllocINTEL_fn> clHostMemAllocINTELCache;
330
- FuncPtrCache<clDeviceMemAllocINTEL_fn> clDeviceMemAllocINTELCache;
331
- FuncPtrCache<clSharedMemAllocINTEL_fn> clSharedMemAllocINTELCache;
332
- FuncPtrCache<clGetDeviceFunctionPointer_fn> clGetDeviceFunctionPointerCache;
333
- FuncPtrCache<clGetDeviceGlobalVariablePointer_fn>
334
- clGetDeviceGlobalVariablePointerCache;
335
- FuncPtrCache<clCreateBufferWithPropertiesINTEL_fn>
336
- clCreateBufferWithPropertiesINTELCache;
337
- FuncPtrCache<clMemBlockingFreeINTEL_fn> clMemBlockingFreeINTELCache;
338
- FuncPtrCache<clSetKernelArgMemPointerINTEL_fn>
339
- clSetKernelArgMemPointerINTELCache;
340
- FuncPtrCache<clEnqueueMemFillINTEL_fn> clEnqueueMemFillINTELCache;
341
- FuncPtrCache<clEnqueueMemcpyINTEL_fn> clEnqueueMemcpyINTELCache;
342
- FuncPtrCache<clGetMemAllocInfoINTEL_fn> clGetMemAllocInfoINTELCache;
343
- FuncPtrCache<clEnqueueWriteGlobalVariable_fn>
344
- clEnqueueWriteGlobalVariableCache;
345
- FuncPtrCache<clEnqueueReadGlobalVariable_fn> clEnqueueReadGlobalVariableCache;
346
- FuncPtrCache<clEnqueueReadHostPipeINTEL_fn> clEnqueueReadHostPipeINTELCache;
347
- FuncPtrCache<clEnqueueWriteHostPipeINTEL_fn> clEnqueueWriteHostPipeINTELCache;
348
- FuncPtrCache<clSetProgramSpecializationConstant_fn>
349
- clSetProgramSpecializationConstantCache;
350
- FuncPtrCache<clCreateCommandBufferKHR_fn> clCreateCommandBufferKHRCache;
351
- FuncPtrCache<clRetainCommandBufferKHR_fn> clRetainCommandBufferKHRCache;
352
- FuncPtrCache<clReleaseCommandBufferKHR_fn> clReleaseCommandBufferKHRCache;
353
- FuncPtrCache<clFinalizeCommandBufferKHR_fn> clFinalizeCommandBufferKHRCache;
354
- FuncPtrCache<clCommandNDRangeKernelKHR_fn> clCommandNDRangeKernelKHRCache;
355
- FuncPtrCache<clCommandCopyBufferKHR_fn> clCommandCopyBufferKHRCache;
356
- FuncPtrCache<clCommandCopyBufferRectKHR_fn> clCommandCopyBufferRectKHRCache;
357
- FuncPtrCache<clCommandFillBufferKHR_fn> clCommandFillBufferKHRCache;
358
- FuncPtrCache<clEnqueueCommandBufferKHR_fn> clEnqueueCommandBufferKHRCache;
359
- FuncPtrCache<clGetCommandBufferInfoKHR_fn> clGetCommandBufferInfoKHRCache;
360
- FuncPtrCache<clUpdateMutableCommandsKHR_fn> clUpdateMutableCommandsKHRCache;
330
+ #define CL_EXTENSION_FUNC (func ) FuncPtrCache<func##_fn> func##Cache;
331
+
332
+ #include " extension_functions.def"
333
+
334
+ #undef CL_EXTENSION_FUNC
335
+
336
+ // If a context stored in the current caching mechanism is destroyed by the
337
+ // CL driver all of its function pointers are invalidated. This can lead to a
338
+ // pathological case where a subsequently created context gets returned with
339
+ // a coincidentally identical handle to the destroyed one and ends up being
340
+ // used to retrieve bad function pointers. To avoid this we clear the cache
341
+ // when contexts are released.
342
+ void clearCache (cl_context context) {
343
+ #define CL_EXTENSION_FUNC (func ) func##Cache.clear(context);
344
+
345
+ #include " extension_functions.def"
346
+
347
+ #undef CL_EXTENSION_FUNC
348
+ }
361
349
};
362
350
// A raw pointer is used here since the lifetime of this map has to be tied to
363
351
// piTeardown to avoid issues with static destruction order (a user application
0 commit comments