diff options
-rw-r--r-- | debian/patches/libports-lockless-refcounting.patch | 294 | ||||
-rw-r--r-- | debian/patches/series | 1 |
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 |