diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-05-14 14:37:15 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-05-14 14:37:15 +0200 |
commit | ee7f257645c32c732864d6629f1c3636569596e8 (patch) | |
tree | 22ae42d6cb2d1e481427893c6b2e85d710bb5bc7 /debian/patches/0006-include-add-refcounts_demote-that-demotes-a-hard-ref.patch | |
parent | 3c11912d3e6b13a3e88b392eaf61cd11ba2c548b (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.patch | 115 |
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 + |