diff options
Diffstat (limited to 'debian/patches/0003-libports-lock-less-reference-counting-for-port_info-.patch')
-rw-r--r-- | debian/patches/0003-libports-lock-less-reference-counting-for-port_info-.patch | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/debian/patches/0003-libports-lock-less-reference-counting-for-port_info-.patch b/debian/patches/0003-libports-lock-less-reference-counting-for-port_info-.patch new file mode 100644 index 00000000..9c5754ed --- /dev/null +++ b/debian/patches/0003-libports-lock-less-reference-counting-for-port_info-.patch @@ -0,0 +1,346 @@ +From 2644982be8c7d742f7d5be02ab9211c72bd356d5 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Sat, 3 May 2014 01:02:35 +0200 +Subject: [PATCH 3/5] libports: lock-less reference counting for port_info + objects + +* libports/refcount.h: New file with reference counting primitives. +* libports/ports.h (struct port_info): Use the new type. +* libports/lookup-port.c: No need to lock _ports_lock anymore. +* libports/bucket-iterate.c: Likewise. +* libports/complete-deallocate.c: Check if someone reacquired a +reference through a hash table lookup. +* libports/create-internal.c: Use the new reference counting primitives. +* libports/get-right.c: Likewise. +* libports/import-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. +* utils/rpctrace.c: Likewise. +--- + libports/bucket-iterate.c | 4 +--- + libports/complete-deallocate.c | 15 +++++++++++++++ + libports/create-internal.c | 3 +-- + libports/get-right.c | 2 +- + libports/import-port.c | 3 +-- + libports/lookup-port.c | 6 ++---- + libports/port-deref-weak.c | 10 +++------- + libports/port-deref.c | 34 ++++++++++++++++------------------ + libports/port-ref-weak.c | 8 +++----- + libports/port-ref.c | 8 +++----- + libports/ports.h | 4 ++-- + libports/reallocate-from-external.c | 2 +- + libports/transfer-right.c | 2 +- + utils/rpctrace.c | 10 ++++++++-- + 14 files changed, 58 insertions(+), 53 deletions(-) + +diff --git a/libports/bucket-iterate.c b/libports/bucket-iterate.c +index d5f590e..2a2b2b6 100644 +--- a/libports/bucket-iterate.c ++++ b/libports/bucket-iterate.c +@@ -35,7 +35,6 @@ _ports_bucket_class_iterate (struct port_bucket *bucket, + size_t i, n, nr_items; + error_t err; + +- pthread_mutex_lock (&_ports_lock); + pthread_mutex_lock (&_ports_htable_lock); + + if (_ports_htable.nr_items == 0) +@@ -60,13 +59,12 @@ _ports_bucket_class_iterate (struct port_bucket *bucket, + if ((bucket == NULL || pi->bucket == bucket) + && (class == NULL || pi->class == class)) + { +- pi->refcnt++; ++ refcounts_ref (&pi->refcounts, NULL); + p[n] = pi; + n++; + } + } + pthread_mutex_unlock (&_ports_htable_lock); +- pthread_mutex_unlock (&_ports_lock); + + if (n == 0) + { +diff --git a/libports/complete-deallocate.c b/libports/complete-deallocate.c +index 1371d92..6c9074a 100644 +--- a/libports/complete-deallocate.c ++++ b/libports/complete-deallocate.c +@@ -29,14 +29,29 @@ _ports_complete_deallocate (struct port_info *pi) + + if (pi->port_right) + { ++ struct references result; ++ + pthread_mutex_lock (&_ports_htable_lock); ++ ++ refcounts_references (&pi->refcounts, &result); ++ if (result.hard > 0 || result.weak > 0) ++ { ++ /* A reference was reacquired through a hash table lookup. ++ It's fine, we didn't touch anything yet. */ ++ pthread_mutex_unlock (&_ports_htable_lock); ++ return; ++ } ++ + hurd_ihash_locp_remove (&_ports_htable, pi->hentry); + pthread_mutex_unlock (&_ports_htable_lock); ++ + mach_port_mod_refs (mach_task_self (), pi->port_right, + MACH_PORT_RIGHT_RECEIVE, -1); + pi->port_right = MACH_PORT_NULL; + } + ++ pthread_mutex_lock (&_ports_lock); ++ + pi->bucket->count--; + pi->class->count--; + +diff --git a/libports/create-internal.c b/libports/create-internal.c +index e773dd6..9e3824d 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; ++ refcounts_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..8681f46 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++; ++ refcounts_ref (&pi->refcounts, NULL); + 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 d0b2ea4..e250b0e 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; ++ refcounts_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 fbb13ef..1bf012f 100644 +--- a/libports/lookup-port.c ++++ b/libports/lookup-port.c +@@ -28,7 +28,6 @@ ports_lookup_port (struct port_bucket *bucket, + { + struct port_info *pi; + +- pthread_mutex_lock (&_ports_lock); + pthread_mutex_lock (&_ports_htable_lock); + + pi = hurd_ihash_find (&_ports_htable, port); +@@ -38,10 +37,9 @@ ports_lookup_port (struct port_bucket *bucket, + pi = 0; + + if (pi) +- pi->refcnt++; ++ ports_port_ref (pi); + + pthread_mutex_unlock (&_ports_htable_lock); +- pthread_mutex_unlock (&_ports_lock); +- ++ + return pi; + } +diff --git a/libports/port-deref-weak.c b/libports/port-deref-weak.c +index beb4842..8432660 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 references result; ++ refcounts_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..dd38f55 100644 +--- a/libports/port-deref.c ++++ b/libports/port-deref.c +@@ -25,26 +25,24 @@ void + ports_port_deref (void *portstruct) + { + struct port_info *pi = portstruct; +- int trieddroppingweakrefs = 0; +- +- retry: +- +- pthread_mutex_lock (&_ports_lock); +- +- if (pi->refcnt == 1 && pi->weakrefcnt +- && pi->class->dropweak_routine && !trieddroppingweakrefs) ++ 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) + { +- pthread_mutex_unlock (&_ports_lock); +- (*pi->class->dropweak_routine) (pi); +- trieddroppingweakrefs = 1; +- goto retry; ++ if (result.hard == 0 && result.weak > 1) ++ (*pi->class->dropweak_routine) (pi); ++ refcounts_deref_weak (&pi->refcounts, &result); + } +- +- 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..e4b7fc8 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 references result; ++ refcounts_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..761c50f 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 references result; ++ refcounts_ref (&pi->refcounts, &result); ++ assert (result.hard > 1 || result.weak > 0); + } +diff --git a/libports/ports.h b/libports/ports.h +index 9c5f14d..116e920 100644 +--- a/libports/ports.h ++++ b/libports/ports.h +@@ -27,6 +27,7 @@ + #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. */ +@@ -39,8 +40,7 @@ + struct port_info + { + struct port_class *class; +- int refcnt; +- int weakrefcnt; ++ refcounts_t 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 bbcf9ba..5ee579d 100644 +--- a/libports/reallocate-from-external.c ++++ b/libports/reallocate-from-external.c +@@ -55,7 +55,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++; ++ refcounts_ref (&pi->refcounts, NULL); + } + + pi->port_right = receive; +diff --git a/libports/transfer-right.c b/libports/transfer-right.c +index 5a7653d..d3ff0f4 100644 +--- a/libports/transfer-right.c ++++ b/libports/transfer-right.c +@@ -70,7 +70,7 @@ ports_transfer_right (void *tostruct, + else if (((topi->flags & PORT_HAS_SENDRIGHTS) == 0) && hassendrights) + { + topi->flags |= PORT_HAS_SENDRIGHTS; +- topi->refcnt++; ++ refcounts_ref (&topi->refcounts, NULL); + } + } + +diff --git a/utils/rpctrace.c b/utils/rpctrace.c +index fc913e3..b11fea4 100644 +--- a/utils/rpctrace.c ++++ b/utils/rpctrace.c +@@ -431,7 +431,9 @@ destroy_receiver_info (struct receiver_info *info) + while (send_wrapper) + { + struct sender_info *next = send_wrapper->next; +- assert (TRACED_INFO (send_wrapper)->pi.refcnt == 1); ++ assert ( ++ refcounts_hard_references (&TRACED_INFO (send_wrapper)->pi.refcounts) ++ == 1); + /* Reset the receive_right of the send wrapper in advance to avoid + * destroy_receiver_info is called when the port info is destroyed. */ + send_wrapper->receive_right = NULL; +@@ -848,7 +850,11 @@ rewrite_right (mach_port_t *right, mach_msg_type_name_t *type, + hurd_ihash_locp_remove (&traced_names, receiver_info->locp); + + send_wrapper2 = get_send_wrapper (receiver_info, dest, &rr); +- assert (TRACED_INFO (send_wrapper2)->pi.refcnt == 1); ++ assert ( ++ refcounts_hard_references ( ++ &TRACED_INFO (send_wrapper2)->pi.refcounts) ++ == 1); ++ + name = TRACED_INFO (send_wrapper2)->name; + TRACED_INFO (send_wrapper2)->name = NULL; + /* send_wrapper2 isn't destroyed normally, so we need to unlink +-- +2.0.0.rc0 + |