summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drm-lease-manager/lease-manager.c93
-rw-r--r--drm-lease-manager/meson.build2
-rw-r--r--meson.build2
3 files changed, 93 insertions, 4 deletions
diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c
index 6fafb46..5d79b8d 100644
--- a/drm-lease-manager/lease-manager.c
+++ b/drm-lease-manager/lease-manager.c
@@ -22,6 +22,8 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -47,6 +49,11 @@ struct lease {
uint32_t *object_ids;
int nobject_ids;
+
+ /* for lease transfer completion */
+ uint32_t crtc_id;
+ pthread_t transition_tid;
+ bool transition_running;
};
struct lm {
@@ -199,6 +206,87 @@ static bool lease_add_planes(struct lm *lm, struct lease *lease, int crtc_index)
return true;
}
+/* Lease transition
+ * Wait for a client to update the DRM framebuffer on the CRTC managed by
+ * a lease. Once the framebuffer has been updated, it is safe to close
+ * the fd associated with the previous lease client, freeing the previous
+ * framebuffer if there are no other references to it. */
+static void wait_for_fb_update(struct lease *lease, uint32_t old_fb)
+{
+ uint32_t current_fb = old_fb;
+
+ struct pollfd drm_poll = {
+ .fd = lease->lease_fd,
+ .events = POLLIN,
+ };
+
+ while (current_fb == old_fb) {
+ drmModeCrtcPtr crtc;
+ if (poll(&drm_poll, 1, -1) < 0) {
+ if (errno == EINTR)
+ continue;
+ break;
+ }
+
+ crtc = drmModeGetCrtc(lease->lease_fd, lease->crtc_id);
+ current_fb = crtc->buffer_id;
+ drmModeFreeCrtc(crtc);
+ }
+}
+
+struct transition_ctx {
+ struct lease *lease;
+ int close_fd;
+ uint32_t old_fb;
+};
+
+static void transition_done(void *arg)
+{
+ struct transition_ctx *ctx = arg;
+ close(ctx->close_fd);
+ free(ctx);
+}
+
+static void *finish_transition_task(void *arg)
+{
+ struct transition_ctx *ctx = arg;
+ pthread_cleanup_push(transition_done, ctx);
+ wait_for_fb_update(ctx->lease, ctx->old_fb);
+ pthread_cleanup_pop(true);
+ return NULL;
+}
+
+static void close_after_lease_transition(struct lease *lease, int close_fd)
+{
+ struct transition_ctx *ctx = calloc(1, sizeof(*ctx));
+
+ assert(ctx);
+
+ drmModeCrtcPtr crtc = drmModeGetCrtc(lease->lease_fd, lease->crtc_id);
+
+ ctx->lease = lease;
+ ctx->close_fd = close_fd;
+ ctx->old_fb = crtc->buffer_id;
+
+ drmModeFreeCrtc(crtc);
+
+ int ret = pthread_create(&lease->transition_tid, NULL,
+ finish_transition_task, ctx);
+
+ lease->transition_running = (ret == 0);
+}
+
+static void cancel_lease_transition_thread(struct lease *lease)
+{
+
+ if (lease->transition_running) {
+ pthread_cancel(lease->transition_tid);
+ pthread_join(lease->transition_tid, NULL);
+ }
+
+ lease->transition_running = false;
+}
+
static void lease_free(struct lease *lease)
{
free(lease->base.name);
@@ -238,6 +326,7 @@ static struct lease *lease_create(struct lm *lm, drmModeConnectorPtr connector)
goto err;
uint32_t crtc_id = lm->drm_resource->crtcs[crtc_index];
+ lease->crtc_id = crtc_id;
lease->object_ids[lease->nobject_ids++] = crtc_id;
lease->object_ids[lease->nobject_ids++] = connector->connector_id;
@@ -381,8 +470,6 @@ int lm_lease_transfer(struct lm *lm, struct lease_handle *handle)
if (!lease->is_granted)
return -1;
- // TODO: close this fd once a frame is presented from the new
- // client.
int old_lease_fd = dup(lease->lease_fd);
lm_lease_revoke(lm, handle);
@@ -391,6 +478,7 @@ int lm_lease_transfer(struct lm *lm, struct lease_handle *handle)
return -1;
}
+ close_after_lease_transition(lease, old_lease_fd);
return lease->lease_fd;
}
@@ -405,6 +493,7 @@ void lm_lease_revoke(struct lm *lm, struct lease_handle *handle)
return;
drmModeRevokeLease(lm->drm_fd, lease->lessee_id);
+ cancel_lease_transition_thread(lease);
close(lease->lease_fd);
lease->is_granted = false;
}
diff --git a/drm-lease-manager/meson.build b/drm-lease-manager/meson.build
index 1171b02..7157f01 100644
--- a/drm-lease-manager/meson.build
+++ b/drm-lease-manager/meson.build
@@ -3,7 +3,7 @@ lease_manager_files = files('lease-manager.c')
lease_server_files = files('lease-server.c')
main = executable('drm-lease-manager',
[ 'main.c', lease_manager_files, lease_server_files ],
- dependencies: [ drm_dep, dlmcommon_dep ],
+ dependencies: [ drm_dep, dlmcommon_dep, thread_dep ],
install: true,
)
diff --git a/meson.build b/meson.build
index 2f6cd15..7f8adf5 100644
--- a/meson.build
+++ b/meson.build
@@ -34,12 +34,12 @@ configure_file(output: 'config.h',
configuration_inc = include_directories('.')
drm_dep = dependency('libdrm', version: '>= 2.4.89')
+thread_dep = dependency('threads')
enable_tests = get_option('enable-tests')
if enable_tests
check_dep = dependency('check')
- thread_dep = dependency('threads')
# Default to the system provided version of fff.h.
# otherwise fetch it ourselves.