diff options
Diffstat (limited to '')
| -rw-r--r-- | src/gem.cpp | 65 | ||||
| -rw-r--r-- | src/ioctl.cpp | 46 | ||||
| -rw-r--r-- | src/syncobject.cpp | 3 |
3 files changed, 67 insertions, 47 deletions
diff --git a/src/gem.cpp b/src/gem.cpp index 0572c3b..b6b3d38 100644 --- a/src/gem.cpp +++ b/src/gem.cpp @@ -4,8 +4,11 @@ #include "drm++/helper.hpp" #include "drm++/ioctl.hpp" +#include <cassert> #include <cerrno> +#include <stdexcept> #include <system_error> +#include <utility> #include <drm.h> #include <drm_mode.h> @@ -18,14 +21,15 @@ using namespace drm::gem; /* GEM object class */ -Object::Object(int fd, int dmabuf_fd, bool close) : m_fd(fd) { +Object::Object(ObjectManager& manager, int dmabuf_fd, bool close) : m_manager(&manager) { try { drm_prime_handle args{ .fd = dmabuf_fd }; - ioctl::perform(this->m_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, args); this->m_handle = args.handle; + this->m_manager->m_refcounts[this->m_handle]++; } catch (...) { if (close) { ::close(dmabuf_fd); @@ -44,22 +48,36 @@ int Object::exportFd(ExportFlags flags) const { .handle = this->m_handle, .flags = static_cast<u32>(flags) }; - ioctl::perform(this->m_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, args); return args.fd; } void Object::changeHandle(u32 handle) { - drm_gem_close args{ - .handle = this->m_handle + auto& refcounts{this->m_manager->m_refcounts}; + if (refcounts[handle] > 0 || refcounts[this->m_handle] > 1) { + throw std::logic_error("GEM handle is still in use"); + } + + drm_gem_change_handle args{ + .handle = this->m_handle, + .new_handle = handle }; - ioctl::perform(this->m_fd, DRM_IOCTL_GEM_CLOSE, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_GEM_CHANGE_HANDLE, args); + std::exchange(refcounts[handle], refcounts[this->m_handle]); this->m_handle = handle; } void Object::destruct() noexcept { - if (this->m_fd < 0) { + if (this->m_manager == nullptr) { + return; + } + + auto& refcounts{this->m_manager->m_refcounts}; + if (refcounts[this->m_handle] > 1) { + refcounts[this->m_handle]--; + this->m_manager = nullptr; return; } @@ -67,26 +85,28 @@ void Object::destruct() noexcept { .handle = this->m_handle }; try { - ioctl::perform(this->m_fd, DRM_IOCTL_GEM_CLOSE, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_GEM_CLOSE, args); } catch(...) { - (void) 0; // not much we can do about the leak + assert(false && "GEM close failed, memory leak likely"); } - this->m_fd = -1; + this->m_manager = nullptr; } /* Dumb buffer class */ -DumbBuffer::DumbBuffer(int fd, u32 width, u32 height, u32 bpp) - : Object(fd), m_width(width), m_height(height), m_bpp(bpp) { +DumbBuffer::DumbBuffer(ObjectManager& manager, u32 width, u32 height, u32 bpp) + : Object(manager), m_width(width), m_height(height), m_bpp(bpp) { drm_mode_create_dumb args{ .height = height, .width = width, .bpp = bpp }; - ioctl::perform(this->m_fd, DRM_IOCTL_MODE_CREATE_DUMB, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_MODE_CREATE_DUMB, args); this->m_handle = args.handle; + this->m_manager->m_refcounts[this->m_handle]++; + this->m_pitch = args.pitch; this->m_size = args.size; } @@ -99,10 +119,10 @@ void* DumbBuffer::map() { drm_mode_map_dumb args{ .handle = this->m_handle }; - ioctl::perform(this->m_fd, DRM_IOCTL_MODE_MAP_DUMB, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_MODE_MAP_DUMB, args); void* map{::mmap(nullptr, this->m_size, PROT_READ | PROT_WRITE, MAP_SHARED, - this->m_fd, static_cast<off_t>(args.offset))}; + this->m_manager->m_fd, static_cast<off_t>(args.offset))}; if (map == MAP_FAILED) { throw std::system_error(errno, std::generic_category(), "mmap failed"); } @@ -112,7 +132,14 @@ void* DumbBuffer::map() { } void DumbBuffer::destruct() noexcept { - if (this->m_fd < 0) { + if (this->m_manager == nullptr) { + return; + } + + auto& refcounts{this->m_manager->m_refcounts}; + if (refcounts[this->m_handle] > 1) { + refcounts[this->m_handle]--; + this->m_manager = nullptr; return; } @@ -125,10 +152,10 @@ void DumbBuffer::destruct() noexcept { .handle = this->m_handle }; try { - ioctl::perform(this->m_fd, DRM_IOCTL_MODE_DESTROY_DUMB, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_MODE_DESTROY_DUMB, args); } catch(...) { - (void) 0; // not much we can do about the leak + assert(false && "Dumb buffer destroy failed, memory leak likely"); } - this->m_fd = -1; + this->m_manager = nullptr; } diff --git a/src/ioctl.cpp b/src/ioctl.cpp index 982e1e9..8b4962f 100644 --- a/src/ioctl.cpp +++ b/src/ioctl.cpp @@ -13,43 +13,35 @@ Exception::Exception(int fd, unsigned long op) : m_fd(fd), m_op(op), m_syserrno(errno) { switch (errno) { case EBADF: - m_code = Error::BadFileDescriptor; + this->m_code = Error::BadFileDescriptor; + this->m_what = std::format( + "ioctl({}, 0x{:x}) failed: Invalid file descriptor", + this->m_fd, this->m_op + ); break; case EINVAL: case ENOTTY: - m_code = Error::InvalidArgument; - break; - case ENOTSUP: - m_code = Error::NotSupported; - break; - default: - m_code = Error::Other; - } -} - -std::string Exception::readable() { - switch (this->m_code) { - case Error::BadFileDescriptor: - return std::format( - "ioctl({}, {}) failed: Invalid file descriptor", - this->m_fd, this->m_op - ); - case Error::InvalidArgument: - return std::format( - "ioctl({}, {}) failed: Invalid argument (errno {})", + this->m_code = Error::InvalidArgument; + this->m_what = std::format( + "ioctl({}, 0x{:x}) failed: Invalid argument (errno {})", this->m_fd, this->m_op, this->m_syserrno ); - case Error::NotSupported: - return std::format( - "ioctl({}, {}) failed: Operation not supported", + break; + case ENOTSUP: + this->m_code = Error::NotSupported; + this->m_what = std::format( + "ioctl({}, 0x{:x}) failed: Operation not supported", this->m_fd, this->m_op ); - case Error::Other: - return std::format( - "ioctl({}, {}) failed: Unknown error (errno {})", + break; + default: + this->m_code = Error::Other; + this->m_what = std::format( + "ioctl({}, 0x{:x}) failed: Unknown error (errno {})", this->m_fd, this->m_op, this->m_syserrno ); } } + Exception::~Exception() = default; diff --git a/src/syncobject.cpp b/src/syncobject.cpp index f2d3bbc..4ec1a9c 100644 --- a/src/syncobject.cpp +++ b/src/syncobject.cpp @@ -4,6 +4,7 @@ #include "drm++/helper.hpp" #include "drm++/ioctl.hpp" +#include <cassert> #include <cstddef> #include <optional> #include <span> @@ -68,7 +69,7 @@ void SyncObjectBase::destruct() noexcept { try { ioctl::perform(this->m_fd, DRM_IOCTL_SYNCOBJ_DESTROY, args); } catch(...) { - (void) 0; // not much we can do about the leak + assert(false && "Sync object destroy failed, memory leak likely"); } this->m_fd = -1; |
