summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/patches/libports-lockless-refcounting.patch294
-rw-r--r--debian/patches/series1
2 files changed, 295 insertions, 0 deletions
diff --git a/debian/patches/libports-lockless-refcounting.patch b/debian/patches/libports-lockless-refcounting.patch
new file mode 100644
index 00000000..5b487da0
--- /dev/null
+++ b/debian/patches/libports-lockless-refcounting.patch
@@ -0,0 +1,294 @@
+commit 7f46aeee292d80d89140f15028067891ab8adddd
+Author: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Sat May 3 01:02:35 2014 +0200
+
+ libports: implement lockless reference counting
+
+ * libports/refcount.h: New file with reference counting primitives.
+ * libports/ports.h (struct port_info): Use the new type.
+ * libports/bucket-iterate.c: Adjust accordingly.
+ * libports/create-internal.c: Likewise.
+ * libports/get-right.c: Likewise.
+ * libports/import-port.c: Likewise.
+ * libports/lookup-port.c: Likewise.
+ * libports/port-deref-weak.c: Likewise.
+ * libports/port-deref.c: Likewise.
+ * libports/port-ref-weak.c: Likewise.
+ * libports/port-ref.c: Likewise.
+ * libports/reallocate-from-external.c: Likewise.
+ * libports/transfer-right.c: Likewise.
+
+diff --git a/libports/bucket-iterate.c b/libports/bucket-iterate.c
+index 498cf13..38a9f7a 100644
+--- a/libports/bucket-iterate.c
++++ b/libports/bucket-iterate.c
+@@ -55,7 +55,7 @@ _ports_bucket_class_iterate (struct port_bucket *bucket,
+
+ if (class == 0 || pi->class == class)
+ {
+- pi->refcnt++;
++ ports_port_ref (pi);
+ p[n] = pi;
+ n++;
+ }
+diff --git a/libports/create-internal.c b/libports/create-internal.c
+index 8551297..d56637c 100644
+--- a/libports/create-internal.c
++++ b/libports/create-internal.c
+@@ -54,8 +54,7 @@ _ports_create_port_internal (struct port_class *class,
+ }
+
+ pi->class = class;
+- pi->refcnt = 1;
+- pi->weakrefcnt = 0;
++ refcount_init (&pi->refcounts, 1, 0);
+ pi->cancel_threshold = 0;
+ pi->mscount = 0;
+ pi->flags = 0;
+diff --git a/libports/get-right.c b/libports/get-right.c
+index 89050c6..42bfa2b 100644
+--- a/libports/get-right.c
++++ b/libports/get-right.c
+@@ -41,7 +41,7 @@ ports_get_right (void *port)
+ if ((pi->flags & PORT_HAS_SENDRIGHTS) == 0)
+ {
+ pi->flags |= PORT_HAS_SENDRIGHTS;
+- pi->refcnt++;
++ ports_port_ref (pi);
+ err = mach_port_request_notification (mach_task_self (),
+ pi->port_right,
+ MACH_NOTIFY_NO_SENDERS,
+diff --git a/libports/import-port.c b/libports/import-port.c
+index 226f47e..5c66685 100644
+--- a/libports/import-port.c
++++ b/libports/import-port.c
+@@ -48,8 +48,7 @@ ports_import_port (struct port_class *class, struct port_bucket *bucket,
+ return ENOMEM;
+
+ pi->class = class;
+- pi->refcnt = 1 + !!stat.mps_srights;
+- pi->weakrefcnt = 0;
++ refcount_init (&pi->refcounts, 1 + !!stat.mps_srights, 0);
+ pi->cancel_threshold = 0;
+ pi->mscount = stat.mps_mscount;
+ pi->flags = stat.mps_srights ? PORT_HAS_SENDRIGHTS : 0;
+diff --git a/libports/lookup-port.c b/libports/lookup-port.c
+index f79f6f0..289369f 100644
+--- a/libports/lookup-port.c
++++ b/libports/lookup-port.c
+@@ -44,7 +44,7 @@ ports_lookup_port (struct port_bucket *bucket,
+ pi = 0;
+
+ if (pi)
+- pi->refcnt++;
++ ports_port_ref (pi);
+
+ pthread_mutex_unlock (&_ports_lock);
+
+diff --git a/libports/port-deref-weak.c b/libports/port-deref-weak.c
+index beb4842..48e5354 100644
+--- a/libports/port-deref-weak.c
++++ b/libports/port-deref-weak.c
+@@ -25,12 +25,8 @@ void
+ ports_port_deref_weak (void *portstruct)
+ {
+ struct port_info *pi = portstruct;
+-
+- pthread_mutex_lock (&_ports_lock);
+- assert (pi->weakrefcnt);
+- pi->weakrefcnt--;
+- if (pi->refcnt == 0 && pi->weakrefcnt == 0)
++ struct refs result;
++ refcount_deref_weak (&pi->refcounts, &result);
++ if (result.hard == 0 && result.weak == 0)
+ _ports_complete_deallocate (pi);
+- else
+- pthread_mutex_unlock (&_ports_lock);
+ }
+diff --git a/libports/port-deref.c b/libports/port-deref.c
+index cf9b238..056159c 100644
+--- a/libports/port-deref.c
++++ b/libports/port-deref.c
+@@ -26,25 +26,19 @@ ports_port_deref (void *portstruct)
+ {
+ struct port_info *pi = portstruct;
+ int trieddroppingweakrefs = 0;
++ struct refs result;
+
+ retry:
+-
+- pthread_mutex_lock (&_ports_lock);
+-
+- if (pi->refcnt == 1 && pi->weakrefcnt
++ refcount_deref (&pi->refcounts, &result);
++ if (result.hard == 0 && result.weak > 1
+ && pi->class->dropweak_routine && !trieddroppingweakrefs)
+ {
+- pthread_mutex_unlock (&_ports_lock);
++ refcount_ref (&pi->refcounts, NULL);
+ (*pi->class->dropweak_routine) (pi);
+ trieddroppingweakrefs = 1;
+ goto retry;
+ }
+-
+- assert (pi->refcnt);
+
+- pi->refcnt--;
+- if (pi->refcnt == 0 && pi->weakrefcnt == 0)
++ if (result.hard == 0 && result.weak == 0)
+ _ports_complete_deallocate (pi);
+- else
+- pthread_mutex_unlock (&_ports_lock);
+ }
+diff --git a/libports/port-ref-weak.c b/libports/port-ref-weak.c
+index c7d3c69..8b75005 100644
+--- a/libports/port-ref-weak.c
++++ b/libports/port-ref-weak.c
+@@ -25,9 +25,7 @@ void
+ ports_port_ref_weak (void *portstruct)
+ {
+ struct port_info *pi = portstruct;
+-
+- pthread_mutex_lock (&_ports_lock);
+- assert (pi->refcnt || pi->weakrefcnt);
+- pi->weakrefcnt++;
+- pthread_mutex_unlock (&_ports_lock);
++ struct refs result;
++ refcount_ref_weak (&pi->refcounts, &result);
++ assert (result.hard > 0 || result.weak > 1);
+ }
+diff --git a/libports/port-ref.c b/libports/port-ref.c
+index 92b7118..6310902 100644
+--- a/libports/port-ref.c
++++ b/libports/port-ref.c
+@@ -25,9 +25,7 @@ void
+ ports_port_ref (void *portstruct)
+ {
+ struct port_info *pi = portstruct;
+-
+- pthread_mutex_lock (&_ports_lock);
+- assert (pi->refcnt || pi->weakrefcnt);
+- pi->refcnt++;
+- pthread_mutex_unlock (&_ports_lock);
++ struct refs result;
++ refcount_ref (&pi->refcounts, &result);
++ assert (result.hard > 1 || result.weak > 0);
+ }
+diff --git a/libports/ports.h b/libports/ports.h
+index 7f13124..7088b2d 100644
+--- a/libports/ports.h
++++ b/libports/ports.h
+@@ -22,12 +22,15 @@
+ #define _HURD_PORTS_
+
+ #include <mach.h>
++#include <stdint.h>
+ #include <stdlib.h>
+ #include <hurd.h>
+ #include <hurd/ihash.h>
+ #include <mach/notify.h>
+ #include <pthread.h>
+
++#include "refcount.h"
++
+ /* These are global values for common flags used in the various structures.
+ Not all of these are meaningful in all flag fields. */
+ #define PORTS_INHIBITED 0x0100 /* block RPC's */
+@@ -39,8 +42,7 @@
+ struct port_info
+ {
+ struct port_class *class;
+- int refcnt;
+- int weakrefcnt;
++ reference_counts refcounts;
+ mach_port_mscount_t mscount;
+ mach_msg_seqno_t cancel_threshold;
+ int flags;
+diff --git a/libports/reallocate-from-external.c b/libports/reallocate-from-external.c
+index 8cccb2a..4dfc59c 100644
+--- a/libports/reallocate-from-external.c
++++ b/libports/reallocate-from-external.c
+@@ -53,7 +53,7 @@ ports_reallocate_from_external (void *portstruct, mach_port_t receive)
+ else if (((pi->flags & PORT_HAS_SENDRIGHTS) == 0) && stat.mps_srights)
+ {
+ pi->flags |= PORT_HAS_SENDRIGHTS;
+- pi->refcnt++;
++ ports_port_ref (pi);
+ }
+
+ pi->port_right = receive;
+diff --git a/libports/refcount.h b/libports/refcount.h
+new file mode 100644
+index 0000000..9f71a85
+--- /dev/null
++++ b/libports/refcount.h
+@@ -0,0 +1,56 @@
++#ifndef _PORTS_REFCOUNT_H_
++#define _PORTS_REFCOUNT_H_
++
++typedef uint64_t reference_counts;
++
++struct refs {
++ uint32_t hard;
++ uint32_t weak;
++};
++
++union _refs {
++ struct refs refs;
++ reference_counts rc;
++};
++
++extern inline void
++refcount_init (reference_counts *ref, uint32_t hard, uint32_t weak)
++{
++ ((union _refs *) ref)->refs =
++ (struct refs) { .hard = hard, .weak = weak };
++}
++
++extern inline void
++refcount_ref (reference_counts *ref, struct refs *result)
++{
++ const union _refs op = { .refs = { .hard = 1 } };
++ reference_counts r = __atomic_add_fetch (ref, op.rc, __ATOMIC_RELAXED);
++ if (result)
++ ((union _refs *) result)->rc = r;
++}
++
++extern inline void
++refcount_deref (reference_counts *ref, struct refs *result)
++{
++ const union _refs op = { .refs = { .hard = 1 } };
++ ((union _refs *) result)->rc =
++ __atomic_sub_fetch (ref, op.rc, __ATOMIC_RELAXED);
++}
++
++extern inline void
++refcount_ref_weak (reference_counts *ref, struct refs *result)
++{
++ const union _refs op = { .refs = { .weak = 1 } };
++ ((union _refs *) result)->rc =
++ __atomic_add_fetch (ref, op.rc, __ATOMIC_RELAXED);
++}
++
++extern inline void
++refcount_deref_weak (reference_counts *ref, struct refs *result)
++{
++ const union _refs op = { .refs = { .weak = 1 } };
++ ((union _refs *) result)->rc =
++ __atomic_sub_fetch (ref, op.rc, __ATOMIC_RELAXED);
++}
++
++#endif /* _PORTS_REFCOUNT_H_ */
+diff --git a/libports/transfer-right.c b/libports/transfer-right.c
+index 72488a9..f4e0c86 100644
+--- a/libports/transfer-right.c
++++ b/libports/transfer-right.c
+@@ -66,7 +66,7 @@ ports_transfer_right (void *tostruct,
+ else if (((topi->flags & PORT_HAS_SENDRIGHTS) == 0) && hassendrights)
+ {
+ topi->flags |= PORT_HAS_SENDRIGHTS;
+- topi->refcnt++;
++ ports_port_ref (topi);
+ }
+ }
+
diff --git a/debian/patches/series b/debian/patches/series
index a4516587..bc5c48b1 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -46,3 +46,4 @@ fatfs-two-pagers.patch
#ext2fs-cache-superblock.patch
libpager-singlethreaded.patch
libpager-drop-seqnos.patch
+libports-lockless-refcounting.patch