summaryrefslogtreecommitdiff
path: root/debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-14 14:37:15 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-14 14:37:15 +0200
commitee7f257645c32c732864d6629f1c3636569596e8 (patch)
tree22ae42d6cb2d1e481427893c6b2e85d710bb5bc7 /debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch
parent3c11912d3e6b13a3e88b392eaf61cd11ba2c548b (diff)
add patch series
Diffstat (limited to 'debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch')
-rw-r--r--debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch115
1 files changed, 115 insertions, 0 deletions
diff --git a/debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch b/debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch
new file mode 100644
index 00000000..2c1fcd3b
--- /dev/null
+++ b/debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch
@@ -0,0 +1,115 @@
+From a1f4af1716aa9c00358816ab7f82dac2cabdd961 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Tue, 13 May 2014 23:04:40 +0200
+Subject: [PATCH 06/13] include: add refcounts_demote that demotes a hard
+ reference
+
+refcounts_demote atomically demotes a hard reference to a weak one.
+This reduces the number of required atomic operations from three to
+two when a hard reference is dropped and a dropweak routine is
+installed.
+
+* include/refcount.h (refcounts_demote): New function.
+* libports/port-deref.c (ports_port_deref): Use the new function.
+---
+ include/refcount.h | 39 +++++++++++++++++++++++++++++++++++++++
+ libports/port-deref.c | 18 +++++++++---------
+ 2 files changed, 48 insertions(+), 9 deletions(-)
+
+diff --git a/include/refcount.h b/include/refcount.h
+index 0816220..2aafb9e 100644
+--- a/include/refcount.h
++++ b/include/refcount.h
+@@ -77,8 +77,18 @@ typedef union _references refcounts_t;
+ /* Instead, the functions manipulating refcounts_t values write the
+ results into this kind of objects. */
+ struct references {
++ /* We chose the layout of this struct so that when it is used in the
++ union _references, the hard reference counts occupy the least
++ significant bits. This way we can implement atomically demoting
++ a hard reference to a weak reference. See refcounts_demote for
++ details. */
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ uint32_t hard;
+ uint32_t weak;
++#else
++ uint32_t weak;
++ uint32_t hard;
++#endif
+ };
+
+ /* We use a union to convert struct reference values to uint64_t which
+@@ -127,6 +137,35 @@ refcounts_deref (refcounts_t *ref, struct references *result)
+ *result = r.references;
+ }
+
++/* Demote a hard reference to a weak reference. If RESULT is not
++ NULL, the result of the operation is written there. This function
++ uses atomic operations. It is not required to serialize calls to
++ this function. */
++static inline void
++refcounts_demote (refcounts_t *ref, struct references *result)
++{
++ /* To demote a hard reference, we need to atomically subtract 1 from
++ the hard reference count, and add 1 to the weak reference
++ count.
++
++ We can subtract by 1 by adding the two's complement of 1 = ~0 to
++ a fixed-width value, discarding the overflow.
++
++ We do the same in our uint64_t value, but we have chosen the
++ layout of struct references so that when it is used in the union
++ _references, the hard reference counts occupy the least
++ significant bits. When we add ~0 to the hard references, it will
++ overflow into the weak references. This is the desired
++ operation. */
++ const union _references op = { .references = { .hard = ~0 } };
++ union _references r;
++ r.value = __atomic_add_fetch (&ref->value, op.value, __ATOMIC_RELAXED);
++ assert (r.references.hard != UINT32_MAX
++ && r.references.weak != UINT32_MAX);
++ if (result)
++ *result = r.references;
++}
++
+ /* Increment the weak reference count of REF. If RESULT is not NULL,
+ the result of the operation is written there. This function uses
+ atomic operations. It is not required to serialize calls to this
+diff --git a/libports/port-deref.c b/libports/port-deref.c
+index dd38f55..b97dd13 100644
+--- a/libports/port-deref.c
++++ b/libports/port-deref.c
+@@ -27,21 +27,21 @@ ports_port_deref (void *portstruct)
+ struct port_info *pi = portstruct;
+ struct references result;
+
+- /* If we need to call the dropweak routine, we need to hold one
+- reference while doing so. We use a weak reference for this
+- purpose, which we acquire before we release our hard reference.
+- The order is important here to prevent a race. */
+- if (pi->class->dropweak_routine)
+- refcounts_ref_weak (&pi->refcounts, NULL);
+-
+- refcounts_deref (&pi->refcounts, &result);
+-
+ if (pi->class->dropweak_routine)
+ {
++ /* If we need to call the dropweak routine, we need to hold one
++ reference while doing so. We use a weak reference for this
++ purpose, which we acquire by demoting our hard reference to a
++ weak one. */
++ refcounts_demote (&pi->refcounts, &result);
++
+ if (result.hard == 0 && result.weak > 1)
+ (*pi->class->dropweak_routine) (pi);
++
+ refcounts_deref_weak (&pi->refcounts, &result);
+ }
++ else
++ refcounts_deref (&pi->refcounts, &result);
+
+ if (result.hard == 0 && result.weak == 0)
+ _ports_complete_deallocate (pi);
+--
+2.0.0.rc0
+