Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2 Draft reservation_object_get_fences_rcu.



details:   https://anonhg.NetBSD.org/src/rev/d3c1d640fde5
branches:  trunk
changeset: 366225:d3c1d640fde5
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Aug 27 14:01:14 2018 +0000

description:
Draft reservation_object_get_fences_rcu.

diffstat:

 sys/external/bsd/drm2/include/linux/reservation.h |    7 +-
 sys/external/bsd/drm2/linux/linux_reservation.c   |  128 +++++++++++++++++++++-
 2 files changed, 132 insertions(+), 3 deletions(-)

diffs (177 lines):

diff -r cac9419cbb75 -r d3c1d640fde5 sys/external/bsd/drm2/include/linux/reservation.h
--- a/sys/external/bsd/drm2/include/linux/reservation.h Mon Aug 27 14:01:01 2018 +0000
+++ b/sys/external/bsd/drm2/include/linux/reservation.h Mon Aug 27 14:01:14 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: reservation.h,v 1.6 2018/08/27 13:55:46 riastradh Exp $        */
+/*     $NetBSD: reservation.h,v 1.7 2018/08/27 14:01:14 riastradh Exp $        */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -58,6 +58,7 @@
 #define        reservation_object_add_shared_fence     linux_reservation_object_add_shared_fence
 #define        reservation_object_fini                 linux_reservation_object_fini
 #define        reservation_object_get_excl             linux_reservation_object_get_excl
+#define        reservation_object_get_fences_rcu       linux_reservation_object_get_fences_rcu
 #define        reservation_object_get_list             linux_reservation_object_get_list
 #define        reservation_object_held                 linux_reservation_object_held
 #define        reservation_object_init                 linux_reservation_object_init
@@ -80,6 +81,10 @@
            struct fence *);
 void   reservation_object_add_shared_fence(struct reservation_object *,
            struct fence *);
+
+int    reservation_object_get_fences_rcu(struct reservation_object *,
+           struct fence **, unsigned *, struct fence ***);
+
 bool   reservation_object_test_signaled_rcu(struct reservation_object *,
            bool);
 long   reservation_object_wait_timeout_rcu(struct reservation_object *,
diff -r cac9419cbb75 -r d3c1d640fde5 sys/external/bsd/drm2/linux/linux_reservation.c
--- a/sys/external/bsd/drm2/linux/linux_reservation.c   Mon Aug 27 14:01:01 2018 +0000
+++ b/sys/external/bsd/drm2/linux/linux_reservation.c   Mon Aug 27 14:01:14 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_reservation.c,v 1.3 2018/08/27 13:55:46 riastradh Exp $  */
+/*     $NetBSD: linux_reservation.c,v 1.4 2018/08/27 14:01:14 riastradh Exp $  */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_reservation.c,v 1.3 2018/08/27 13:55:46 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_reservation.c,v 1.4 2018/08/27 14:01:14 riastradh Exp $");
 
 #include <linux/fence.h>
 #include <linux/reservation.h>
@@ -444,6 +444,130 @@
                fence_put(replace);
 }
 
+int
+reservation_object_get_fences_rcu(struct reservation_object *robj,
+    struct fence **fencep, unsigned *nsharedp, struct fence ***sharedp)
+{
+       struct reservation_object_list *list;
+       struct fence *fence;
+       struct fence **shared = NULL;
+       unsigned shared_alloc, shared_count, i;
+       struct reservation_object_read_ticket ticket;
+
+top:
+       /* Enter an RCU read section and get a read ticket.  */
+       rcu_read_lock();
+       reservation_object_read_begin(robj, &ticket);
+
+       /* If there is a shared list, grab it.  */
+       if ((list = robj->robj_list) != NULL) {
+               /* Make sure the content of the list has been published.  */
+               membar_datadep_consumer();
+
+               /* Check whether we have a buffer.  */
+               if (shared == NULL) {
+                       /*
+                        * We don't have a buffer yet.  Try to allocate
+                        * one without waiting.
+                        */
+                       shared_alloc = list->shared_max;
+                       __insn_barrier();
+                       shared = kcalloc(shared_alloc, sizeof(shared[0]),
+                           GFP_NOWAIT);
+                       if (shared == NULL) {
+                               /*
+                                * Couldn't do it immediately.  Back
+                                * out of RCU and allocate one with
+                                * waiting.
+                                */
+                               rcu_read_unlock();
+                               shared = kcalloc(shared_alloc,
+                                   sizeof(shared[0]), GFP_KERNEL);
+                               if (shared == NULL)
+                                       return -ENOMEM;
+                               goto top;
+                       }
+               } else if (shared_alloc < list->shared_max) {
+                       /*
+                        * We have a buffer but it's too small.  We're
+                        * already racing in this case, so just back
+                        * out and wait to allocate a bigger one.
+                        */
+                       shared_alloc = list->shared_max;
+                       __insn_barrier();
+                       rcu_read_unlock();
+                       kfree(shared);
+                       shared = kcalloc(shared_alloc, sizeof(shared[0]),
+                           GFP_KERNEL);
+                       if (shared == NULL)
+                               return -ENOMEM;
+               }
+
+               /*
+                * We got a buffer large enough.  Copy into the buffer
+                * and record the number of elements.
+                */
+               memcpy(shared, list->shared, shared_alloc * sizeof(shared[0]));
+               shared_count = list->shared_count;
+       } else {
+               /* No shared list: shared count is zero.  */
+               shared_count = 0;
+       }
+
+       /* If there is an exclusive fence, grab it.  */
+       if ((fence = robj->robj_fence) != NULL) {
+               /* Make sure the content of the fence has been published.  */
+               membar_datadep_consumer();
+       }
+
+       /*
+        * We are done reading from robj and list.  Validate our
+        * parking ticket.  If it's invalid, do not pass go and do not
+        * collect $200.
+        */
+       if (!reservation_object_read_valid(robj, &ticket))
+               goto restart;
+
+       /*
+        * Try to get a reference to the exclusive fence, if there is
+        * one.  If we can't, start over.
+        */
+       if (fence) {
+               if (fence_get_rcu(fence) == NULL)
+                       goto restart;
+       }
+
+       /*
+        * Try to get a reference to all of the shared fences.
+        */
+       for (i = 0; i < shared_count; i++) {
+               if (fence_get_rcu(shared[i]) == NULL)
+                       goto put_restart;
+       }
+
+       /* Success!  */
+       rcu_read_unlock();
+       *fencep = fence;
+       *nsharedp = shared_count;
+       *sharedp = shared;
+       return 0;
+
+put_restart:
+       /* Back out.  */
+       while (i --> 0) {
+               fence_put(shared[i]);
+               shared[i] = NULL; /* paranoia */
+       }
+       if (fence) {
+               fence_put(fence);
+               fence = NULL;   /* paranoia */
+       }
+
+restart:
+       rcu_read_unlock();
+       goto top;
+}
+
 /*
  * reservation_object_test_signaled_rcu(robj, shared)
  *



Home | Main Index | Thread Index | Old Index