Add support for lease transition 11/26211/3
authorDamian Hobson-Garcia <dhobsong@igel.co.jp>
Tue, 9 Mar 2021 05:58:22 +0000 (14:58 +0900)
committerDamian Hobson-Garcia <dhobsong@igel.co.jp>
Tue, 6 Apr 2021 01:33:11 +0000 (10:33 +0900)
When enabled allow the ownership of a lease to transition from
one client to another.

If a request is made for a lease that is already allocated to
a client, revoke the lease from the old client and issue a new
lease for the same resources to the new client.

This allows the ownership of the leased resources to be transferred
without the display being closed and the screen blanking.

During the tranistion, hold a reference to the old clients lease fd so
that the last frame presented by the old client will remain on screen until
the new client presents its first frame.

Currenly there is no notification or authentication mechanism
implemeted for the transition.  Any client can request a transition
from any other. The only notification that a transfer has happened
is that the previous client's DRM API calls will suddenly fail with
-ENOENT, since all resources will have been removed.
It is up to the client to sensibly handle this condition.

Bug-AGL: SPEC-3816

Change-Id: Iaff87e275f909f3b6ef448df39364d6fe62007b1
Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>
README.md
drm-lease-manager/drm-lease.h
drm-lease-manager/lease-manager.c
drm-lease-manager/lease-manager.h
drm-lease-manager/main.c

index 5368f6b..84af0a7 100644 (file)
--- a/README.md
+++ b/README.md
@@ -44,6 +44,26 @@ The names of the DRM leases will have the following pattern:
 So, for example, a DRM lease for the first LVDS device on the device `/dev/dri/card0` would be named
 `card0-LVDS-1`.
 
+### Dynamic lease transfer
+
+When `drm-lease-manager` is started with the `-t` option, the
+ownership of a leases resourses can be transfered from
+one client to another.
+
+This allows the ownership of the leased resources to be transferred
+without the display being closed and the screen blanking.
+`drm-lease-manager` handles the timing of the tranfser and manages the
+references to the DRM device, so that the last framebuffer of
+the old client stays on screen until the new client presents its first frame.
+
+The transition can be completed without direct communication between the old
+and new client applications, however, the client that the lease will be
+transitioned *from* must be able to handle unexpected lease revokation.
+Once the lease is revoked, all DRM API calls referring to the DRM
+resources managed by the lease will fail with -ENOENT.  The client
+should be able to gracefully handle this condition by, for example,
+pausing or shutting down its rendering operations.
+
 ## Client API usage
 
 The libdmclient handles all communication with the DRM Lease Manager and provides file descriptors that
index 6c618a0..a855054 100644 (file)
@@ -18,5 +18,6 @@
 
 struct lease_handle {
        char *name;
+       void *user_data;
 };
 #endif
index 016f318..6fafb46 100644 (file)
@@ -372,6 +372,28 @@ int lm_lease_grant(struct lm *lm, struct lease_handle *handle)
        return lease->lease_fd;
 }
 
+int lm_lease_transfer(struct lm *lm, struct lease_handle *handle)
+{
+       assert(lm);
+       assert(handle);
+
+       struct lease *lease = (struct lease *)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);
+               return -1;
+       }
+
+       return lease->lease_fd;
+}
+
 void lm_lease_revoke(struct lm *lm, struct lease_handle *handle)
 {
        assert(lm);
index ed5bcdc..581e05c 100644 (file)
@@ -25,5 +25,6 @@ void lm_destroy(struct lm *lm);
 int lm_get_lease_handles(struct lm *lm, struct lease_handle ***lease_handles);
 
 int lm_lease_grant(struct lm *lm, struct lease_handle *lease_handle);
+int lm_lease_transfer(struct lm *lm, struct lease_handle *lease_handle);
 void lm_lease_revoke(struct lm *lm, struct lease_handle *lease_handle);
 #endif
index 491c80c..78ff0df 100644 (file)
@@ -27,14 +27,16 @@ static void usage(const char *progname)
        printf("Usage: %s [OPTIONS] [<DRM device>]\n\n"
               "Options:\n"
               "-h, --help \tPrint this help\n"
-              "-v, --verbose \tEnable verbose debug messages\n",
+              "-v, --verbose \tEnable verbose debug messages\n"
+              "-t, --lease-transfer \tAllow lease transfter to new clients\n",
               progname);
 }
 
-const char *opts = "vh";
+const char *opts = "vth";
 const struct option options[] = {
     {"help", no_argument, NULL, 'h'},
     {"verbose", no_argument, NULL, 'v'},
+    {"lease-transfer", no_argument, NULL, 't'},
     {NULL, 0, NULL, 0},
 };
 
@@ -43,6 +45,7 @@ int main(int argc, char **argv)
        char *device = "/dev/dri/card0";
 
        bool debug_log = false;
+       bool can_transfer_leases = false;
 
        int c;
        while ((c = getopt_long(argc, argv, opts, options, NULL)) != -1) {
@@ -51,6 +54,9 @@ int main(int argc, char **argv)
                case 'v':
                        debug_log = true;
                        break;
+               case 't':
+                       can_transfer_leases = true;
+                       break;
                case 'h':
                        ret = EXIT_SUCCESS;
                        /* fall through */
@@ -87,6 +93,10 @@ int main(int argc, char **argv)
                switch (req.type) {
                case LS_REQ_GET_LEASE: {
                        int fd = lm_lease_grant(lm, req.lease_handle);
+
+                       if (fd < 0 && can_transfer_leases)
+                               fd = lm_lease_transfer(lm, req.lease_handle);
+
                        if (fd < 0) {
                                ERROR_LOG(
                                    "Can't fulfill lease request: lease=%s\n",
@@ -95,6 +105,13 @@ int main(int argc, char **argv)
                                break;
                        }
 
+                       struct ls_client *active_client =
+                           req.lease_handle->user_data;
+                       if (active_client)
+                               ls_disconnect_client(ls, active_client);
+
+                       req.lease_handle->user_data = req.client;
+
                        if (!ls_send_fd(ls, req.client, fd)) {
                                ERROR_LOG(
                                    "Client communication error: lease=%s\n",
@@ -106,6 +123,7 @@ int main(int argc, char **argv)
                }
                case LS_REQ_RELEASE_LEASE:
                        ls_disconnect_client(ls, req.client);
+                       req.lease_handle->user_data = NULL;
                        lm_lease_revoke(lm, req.lease_handle);
                        break;
                default: