X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=drm-lease-manager%2Flease-manager.c;h=5eeef1688f90ff1a0b5fbfea59c0845bec748388;hb=refs%2Ftags%2Flamprey_12.1.18;hp=6fafb46da983eea81cad0eb2c375916d2abd9b34;hpb=bdf7c337439ff0b70b67462c1f00f5b61942e76a;p=src%2Fdrm-lease-manager.git diff --git a/drm-lease-manager/lease-manager.c b/drm-lease-manager/lease-manager.c index 6fafb46..5eeef16 100644 --- a/drm-lease-manager/lease-manager.c +++ b/drm-lease-manager/lease-manager.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -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,10 +326,12 @@ 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; lease->is_granted = false; + lease->lease_fd = -1; return lease; @@ -328,7 +418,9 @@ void lm_destroy(struct lm *lm) assert(lm); for (int i = 0; i < lm->nleases; i++) { - lm_lease_revoke(lm, (struct lease_handle *)lm->leases[i]); + struct lease_handle *lease_handle = &lm->leases[i]->base; + lm_lease_revoke(lm, lease_handle); + lm_lease_close(lease_handle); lease_free(lm->leases[i]); } @@ -359,17 +451,24 @@ int lm_lease_grant(struct lm *lm, struct lease_handle *handle) return -1; } - lease->lease_fd = + int lease_fd = drmModeCreateLease(lm->drm_fd, lease->object_ids, lease->nobject_ids, 0, &lease->lessee_id); - if (lease->lease_fd < 0) { + if (lease_fd < 0) { ERROR_LOG("drmModeCreateLease failed on lease %s: %s\n", lease->base.name, strerror(errno)); return -1; } lease->is_granted = true; - return lease->lease_fd; + + int old_lease_fd = lease->lease_fd; + lease->lease_fd = lease_fd; + + if (old_lease_fd >= 0) + close_after_lease_transition(lease, old_lease_fd); + + return lease_fd; } int lm_lease_transfer(struct lm *lm, struct lease_handle *handle) @@ -381,13 +480,9 @@ 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); if (lm_lease_grant(lm, handle) < 0) { - close(old_lease_fd); + lm_lease_close(handle); return -1; } @@ -405,6 +500,16 @@ void lm_lease_revoke(struct lm *lm, struct lease_handle *handle) return; drmModeRevokeLease(lm->drm_fd, lease->lessee_id); - close(lease->lease_fd); + cancel_lease_transition_thread(lease); lease->is_granted = false; } + +void lm_lease_close(struct lease_handle *handle) +{ + assert(handle); + + struct lease *lease = (struct lease *)handle; + if (lease->lease_fd >= 0) + close(lease->lease_fd); + lease->lease_fd = -1; +}