clover: track allocated svm pointers

We need those to proper validate the SVM API.

v2: use std::map instead of std::unordered_map
v3: guard against segfaults on std::prev with empty containers

Signed-off-by: Karol Herbst <kherbst@redhat.com>
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6401>
This commit is contained in:
Karol Herbst 2020-08-20 17:05:13 +02:00 committed by Marge Bot
parent e3c2432b37
commit 3718938c1a
4 changed files with 53 additions and 3 deletions

View file

@ -519,6 +519,10 @@ clSVMAlloc(cl_context d_ctx,
if (alignment < sizeof(void*))
alignment = sizeof(void*);
posix_memalign(&ptr, alignment, size);
if (ptr)
ctx.add_svm_allocation(ptr, size);
return ptr;
}
#endif
@ -540,8 +544,10 @@ clSVMFree(cl_context d_ctx,
bool can_emulate = all_of(std::mem_fn(&device::has_system_svm), ctx.devices());
if (can_emulate)
if (can_emulate) {
ctx.remove_svm_allocation(svm_pointer);
return free(svm_pointer);
}
CLOVER_NOT_SUPPORTED_UNTIL("2.0");

View file

@ -969,10 +969,13 @@ clover::EnqueueSVMFree(cl_command_queue d_q,
CLOVER_NOT_SUPPORTED_UNTIL("2.0");
return CL_INVALID_VALUE;
}
pfn_free_func = [](cl_command_queue, cl_uint num_svm_pointers,
pfn_free_func = [](cl_command_queue d_q, cl_uint num_svm_pointers,
void *svm_pointers[], void *) {
for (void *p : range(svm_pointers, num_svm_pointers))
clover::context &ctx = obj(d_q).context();
for (void *p : range(svm_pointers, num_svm_pointers)) {
ctx.remove_svm_allocation(p);
free(p);
}
};
}

View file

@ -61,3 +61,32 @@ context::device_range
context::devices() const {
return map(evals(), devs);
}
void
context::add_svm_allocation(const void *ptr, size_t size) {
svm_ptrs.emplace(ptr, size);
}
void
context::remove_svm_allocation(const void *ptr) {
svm_ptrs.erase(ptr);
}
context::svm_pointer_map::value_type
context::find_svm_allocation(const void *ptr) const {
// std::prev on an iterator of an empty container causes SIGSEGVs
if (svm_ptrs.empty())
return { nullptr, 0 };
auto it = std::prev(svm_ptrs.upper_bound(ptr));
if (it == svm_ptrs.end())
return { nullptr, 0 };
uintptr_t base = reinterpret_cast<uintptr_t>((*it).first);
uintptr_t end = (*it).second + base;
uintptr_t ptrv = reinterpret_cast<uintptr_t>(ptr);
if (ptrv >= base && ptrv < end)
return *it;
return { nullptr, 0 };
}

View file

@ -23,6 +23,7 @@
#ifndef CLOVER_CORE_CONTEXT_HPP
#define CLOVER_CORE_CONTEXT_HPP
#include <map>
#include <stack>
#include "core/object.hpp"
@ -41,6 +42,7 @@ namespace clover {
~context();
typedef std::function<void (const char *)> notify_action;
typedef std::map<const void *, size_t> svm_pointer_map;
context(const property_list &props, const ref_vector<device> &devs,
const notify_action &notify);
@ -62,12 +64,22 @@ namespace clover {
device_range
devices() const;
void
add_svm_allocation(const void *ptr, size_t size);
void
remove_svm_allocation(const void *ptr);
svm_pointer_map::value_type
find_svm_allocation(const void *ptr) const;
const notify_action notify;
private:
property_list props;
const std::vector<intrusive_ref<device>> devs;
std::stack<std::function<void ()>> _destroy_notify;
svm_pointer_map svm_ptrs;
};
}