diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-04 13:57:49 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-04 13:57:49 +0200 |
commit | 7d371354202d8e2de8f09d86751d07c099c94dd9 (patch) | |
tree | 667f0be76c5e60206db0b6234d2d38fc3daf49b2 /debian | |
parent | beb745eaf9cefa0171203795bd00f0b7ca4b82f7 (diff) |
add patch series
Diffstat (limited to 'debian')
-rw-r--r-- | debian/patches/0001-libports-use-protected-payloads-to-optimize-the-obje.patch | 364 | ||||
-rw-r--r-- | debian/patches/0002-xxx-fix-and-assert-reached.patch | 26 | ||||
-rw-r--r-- | debian/patches/0003-new-design.patch | 452 | ||||
-rw-r--r-- | debian/patches/0004-renamed-stuff.patch | 280 | ||||
-rw-r--r-- | debian/patches/series | 4 |
5 files changed, 1126 insertions, 0 deletions
diff --git a/debian/patches/0001-libports-use-protected-payloads-to-optimize-the-obje.patch b/debian/patches/0001-libports-use-protected-payloads-to-optimize-the-obje.patch new file mode 100644 index 00000000..c5575573 --- /dev/null +++ b/debian/patches/0001-libports-use-protected-payloads-to-optimize-the-obje.patch @@ -0,0 +1,364 @@ +From baa1d1e45d73ca0e5a402bae6e183ab22a176824 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Sat, 23 Nov 2013 16:12:55 +0100 +Subject: [PATCH hurd 1/4] libports: use protected payloads to optimize the + object lookup + +* libports/create-internal.c (_ports_create_port_internal): Set the +protected payload to the objects address. +* libports/import-port.c (ports_import_port): Likewise. +* libports/reallocate-from-external.c (ports_reallocate_from_external): +Likewise. +* libports/reallocate-port.c (ports_reallocate_port): Likewise. +* libports/transfer-right.c (ports_transfer_right): Likewise. +* libports/manage-multithread.c (ports_manage_port_operations_multithread): +Use the protected payload as the objects address if provided. +* libports/manage-one-thread.c (ports_manage_port_operations_one_thread): +Likewise. +* libports/destroy-right.c (ports_destroy_right): Defer the +dereferencing of outstanding send rights to avoid a port_info +use-after-free if a no-senders notification is dispatched. +(struct deferred_dereference, gc_loop, start_gc, defer_dereferencing): +Simple generational garbage collection of outstanding send rights. +--- + libports/complete-deallocate.c | 2 +- + libports/create-internal.c | 6 +- + libports/destroy-right.c | 133 ++++++++++++++++++++++++++++++++++-- + libports/import-port.c | 6 +- + libports/manage-multithread.c | 22 +++++- + libports/manage-one-thread.c | 22 +++++- + libports/reallocate-from-external.c | 4 ++ + libports/reallocate-port.c | 4 ++ + libports/transfer-right.c | 3 + + 9 files changed, 193 insertions(+), 9 deletions(-) + +diff --git a/libports/complete-deallocate.c b/libports/complete-deallocate.c +index 0d852f5..6799dfd 100644 +--- a/libports/complete-deallocate.c ++++ b/libports/complete-deallocate.c +@@ -27,7 +27,7 @@ _ports_complete_deallocate (struct port_info *pi) + { + assert ((pi->flags & PORT_HAS_SENDRIGHTS) == 0); + +- if (pi->port_right) ++ if (MACH_PORT_VALID (pi->port_right)) + { + struct references result; + +diff --git a/libports/create-internal.c b/libports/create-internal.c +index 2d85931..d79dc78 100644 +--- a/libports/create-internal.c ++++ b/libports/create-internal.c +@@ -99,7 +99,11 @@ _ports_create_port_internal (struct port_class *class, + bucket->count++; + class->count++; + pthread_mutex_unlock (&_ports_lock); +- ++ ++ /* This is an optimization. It may fail. */ ++ mach_port_set_protected_payload (mach_task_self (), port, ++ (unsigned long) pi); ++ + if (install) + { + err = mach_port_move_member (mach_task_self (), pi->port_right, +diff --git a/libports/destroy-right.c b/libports/destroy-right.c +index 448b379..c229d77 100644 +--- a/libports/destroy-right.c ++++ b/libports/destroy-right.c +@@ -1,5 +1,5 @@ + /* +- Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc. ++ Copyright (C) 1995, 1996, 1999, 2014 Free Software Foundation, Inc. + Written by Michael I. Bushnell. + + This file is part of the GNU Hurd. +@@ -22,30 +22,155 @@ + #include <hurd/ihash.h> + #include <assert.h> + ++#include <pthread.h> ++#include <error.h> ++#include <time.h> ++#include <unistd.h> ++ ++/* To prevent protected payloads from becoming stale, we defer the ++ derefercing of port_info objects. Consumes PI. */ ++static error_t defer_dereferencing (struct port_info *pi); ++ + error_t + ports_destroy_right (void *portstruct) + { + struct port_info *pi = portstruct; + error_t err; + ++ mach_port_clear_protected_payload (mach_task_self (), ++ pi->port_right); ++ ++ pthread_mutex_lock (&_ports_lock); + if (pi->port_right != MACH_PORT_NULL) + { + pthread_rwlock_wrlock (&_ports_htable_lock); + hurd_ihash_locp_remove (&_ports_htable, pi->ports_htable_entry); + hurd_ihash_locp_remove (&pi->bucket->htable, pi->hentry); + pthread_rwlock_unlock (&_ports_htable_lock); ++ + err = mach_port_mod_refs (mach_task_self (), pi->port_right, + MACH_PORT_RIGHT_RECEIVE, -1); + assert_perror (err); + +- pi->port_right = MACH_PORT_NULL; +- + if (pi->flags & PORT_HAS_SENDRIGHTS) + { + pi->flags &= ~PORT_HAS_SENDRIGHTS; +- ports_port_deref (pi); ++ ++ /* There are outstanding send rights, so we might get a ++ no-senders notification. Attached to the notification ++ is a reference to the port_info object. Of course we ++ destroyed the receive right these were send to above, but ++ the message could already have been send and dequeued. ++ ++ Previously, those messages would have carried an stale ++ name, which would have caused a hash table lookup ++ failure. However, stale payloads results in port_info ++ use-after-free. Therefore, we cannot release the ++ reference here, but defer that instead. */ ++ defer_dereferencing (pi); + } ++ ++ pi->port_right = MACH_PORT_DEAD; + } ++ pthread_mutex_unlock (&_ports_lock); ++ ++ return 0; ++} ++ ++/* Simple lock-less generational garbage collection. */ ++ ++/* We maintain three lists of objects. Producers add objects to the ++ current generation G using defer_dereferencing. G-1 holds old ++ objects, G-2 holds garbage. */ ++static struct deferred_dereference ++{ ++ struct deferred_dereference *next; ++ struct port_info *pi; /* We hold a reference for these objects. */ ++} *generations[3]; /* Must be accessed using atomic ++ operations. */ ++ ++/* The current generation. Must be accessed using atomic operations. */ ++static int generation; ++ ++/* The garbage collection thread. Does not return. */ ++static void * ++gc_loop (void *arg) ++{ ++ while (1) ++ { ++ int old, garbage; ++ struct deferred_dereference *d; ++ ++ sleep (5); ++ ++ /* We are the only one updating generation, so this is safe. */ ++ old = generation; ++ ++ /* Update generation. */ ++ __atomic_store_n (&generation, (old + 1) % 3, __ATOMIC_RELAXED); ++ ++ /* This is the garbage generation. As all writers are long ++ gone, we do not need to bother with atomic operations. */ ++ garbage = (old + 2) % 3; ++ d = generations[garbage]; ++ generations[garbage] = NULL; ++ while (d != NULL) ++ { ++ struct deferred_dereference *next = d->next; ++ ++ /* Get rid of our reference. */ ++ ports_port_deref (d->pi); ++ ++ free (d); ++ d = next; ++ } ++ } ++ ++ assert (! "reached"); ++ return NULL; ++} ++ ++/* Start the gc thread. */ ++static void ++start_gc (void) ++{ ++ error_t err; ++ pthread_attr_t attr; ++ pthread_t thread; ++ ++ pthread_attr_init (&attr); ++#define STACK_SIZE (64 * 1024) ++ pthread_attr_setstacksize (&attr, STACK_SIZE); ++#undef STACK_SIZE ++ ++ err = pthread_create (&thread, &attr, gc_loop, NULL); ++ assert_perror (err); ++ err = pthread_detach (thread); ++ assert_perror (err); ++} ++ ++/* Defer the derefercing of port_info objects. Consumes PI. */ ++static error_t ++defer_dereferencing (struct port_info *pi) ++{ ++ static pthread_once_t once = PTHREAD_ONCE_INIT; ++ int g; ++ struct deferred_dereference *d; ++ pthread_once (&once, start_gc); ++ ++ d = malloc (sizeof *d); ++ if (d == NULL) ++ return ENOMEM; ++ d->pi = pi; ++ ++ retry: ++ /* Append to the current generation. */ ++ g = __atomic_load_n (&generation, __ATOMIC_RELAXED); ++ ++ d->next = __atomic_load_n (&generations[g], __ATOMIC_RELAXED); ++ if (! __atomic_compare_exchange_n (&generations[g], &d->next, d, ++ 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) ++ goto retry; + + return 0; + } +diff --git a/libports/import-port.c b/libports/import-port.c +index c337c85..2c638e1 100644 +--- a/libports/import-port.c ++++ b/libports/import-port.c +@@ -93,7 +93,11 @@ ports_import_port (struct port_class *class, struct port_bucket *bucket, + bucket->count++; + class->count++; + pthread_mutex_unlock (&_ports_lock); +- ++ ++ /* This is an optimization. It may fail. */ ++ mach_port_set_protected_payload (mach_task_self (), port, ++ (unsigned long) pi); ++ + mach_port_move_member (mach_task_self (), port, bucket->portset); + + if (stat.mps_srights) +diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c +index 58814d2..9a5278e 100644 +--- a/libports/manage-multithread.c ++++ b/libports/manage-multithread.c +@@ -167,7 +167,27 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket, + outp->RetCodeType = RetCodeType; + outp->RetCode = MIG_BAD_ID; + +- pi = ports_lookup_port (bucket, inp->msgh_local_port, 0); ++ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == ++ MACH_MSG_TYPE_PROTECTED_PAYLOAD) ++ { ++ pi = (struct port_info *) inp->msgh_protected_payload; ++ if (pi && pi->bucket == bucket) ++ ports_port_ref (pi); ++ else ++ pi = NULL; ++ } ++ else ++ { ++ pi = ports_lookup_port (bucket, inp->msgh_local_port, 0); ++ if (pi) ++ { ++ inp->msgh_bits = MACH_MSGH_BITS ( ++ MACH_MSGH_BITS_REMOTE (inp->msgh_bits), ++ MACH_MSG_TYPE_PROTECTED_PAYLOAD); ++ inp->msgh_protected_payload = (unsigned long) pi; ++ } ++ } ++ + if (pi) + { + error_t err = ports_begin_rpc (pi, inp->msgh_id, &link); +diff --git a/libports/manage-one-thread.c b/libports/manage-one-thread.c +index cbd2df7..58c0f36 100644 +--- a/libports/manage-one-thread.c ++++ b/libports/manage-one-thread.c +@@ -57,7 +57,27 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket, + outp->RetCodeType = RetCodeType; + outp->RetCode = MIG_BAD_ID; + +- pi = ports_lookup_port (bucket, inp->msgh_local_port, 0); ++ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == ++ MACH_MSG_TYPE_PROTECTED_PAYLOAD) ++ { ++ pi = (struct port_info *) inp->msgh_protected_payload; ++ if (pi && pi->bucket == bucket) ++ ports_port_ref (pi); ++ else ++ pi = NULL; ++ } ++ else ++ { ++ pi = ports_lookup_port (bucket, inp->msgh_local_port, 0); ++ if (pi) ++ { ++ inp->msgh_bits = MACH_MSGH_BITS ( ++ MACH_MSGH_BITS_REMOTE (inp->msgh_bits), ++ MACH_MSG_TYPE_PROTECTED_PAYLOAD); ++ inp->msgh_protected_payload = (unsigned long) pi; ++ } ++ } ++ + if (pi) + { + err = ports_begin_rpc (pi, inp->msgh_id, &link); +diff --git a/libports/reallocate-from-external.c b/libports/reallocate-from-external.c +index 7205bd9..d0fae1a 100644 +--- a/libports/reallocate-from-external.c ++++ b/libports/reallocate-from-external.c +@@ -71,6 +71,10 @@ ports_reallocate_from_external (void *portstruct, mach_port_t receive) + pthread_mutex_unlock (&_ports_lock); + assert_perror (err); + ++ /* This is an optimization. It may fail. */ ++ mach_port_set_protected_payload (mach_task_self (), pi->port_right, ++ (unsigned long) pi); ++ + mach_port_move_member (mach_task_self (), receive, pi->bucket->portset); + + if (stat.mps_srights) +diff --git a/libports/reallocate-port.c b/libports/reallocate-port.c +index cc534eb..4e859a1 100644 +--- a/libports/reallocate-port.c ++++ b/libports/reallocate-port.c +@@ -59,6 +59,10 @@ ports_reallocate_port (void *portstruct) + pthread_mutex_unlock (&_ports_lock); + assert_perror (err); + ++ /* This is an optimization. It may fail. */ ++ mach_port_set_protected_payload (mach_task_self (), pi->port_right, ++ (unsigned long) pi); ++ + err = mach_port_move_member (mach_task_self (), pi->port_right, + pi->bucket->portset); + assert_perror (err); +diff --git a/libports/transfer-right.c b/libports/transfer-right.c +index 776a8d2..64de7f7 100644 +--- a/libports/transfer-right.c ++++ b/libports/transfer-right.c +@@ -91,6 +91,9 @@ ports_transfer_right (void *tostruct, + err = hurd_ihash_add (&topi->bucket->htable, port, topi); + pthread_rwlock_unlock (&_ports_htable_lock); + assert_perror (err); ++ /* This is an optimization. It may fail. */ ++ mach_port_set_protected_payload (mach_task_self (), port, ++ (unsigned long) topi); + if (topi->bucket != frompi->bucket) + { + err = mach_port_move_member (mach_task_self (), port, +-- +2.1.4 + diff --git a/debian/patches/0002-xxx-fix-and-assert-reached.patch b/debian/patches/0002-xxx-fix-and-assert-reached.patch new file mode 100644 index 00000000..b89b0d3a --- /dev/null +++ b/debian/patches/0002-xxx-fix-and-assert-reached.patch @@ -0,0 +1,26 @@ +From bfa67266242b4457cfa108f72c9f000381518c26 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Fri, 3 Apr 2015 23:03:01 +0200 +Subject: [PATCH hurd 2/4] xxx fix, and assert !reached + +--- + libports/complete-deallocate.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libports/complete-deallocate.c b/libports/complete-deallocate.c +index 6799dfd..c81425e 100644 +--- a/libports/complete-deallocate.c ++++ b/libports/complete-deallocate.c +@@ -37,7 +37,8 @@ _ports_complete_deallocate (struct port_info *pi) + { + /* A reference was reacquired through a hash table lookup. + It's fine, we didn't touch anything yet. */ +- pthread_mutex_unlock (&_ports_htable_lock); ++ assert (! "reacquired reference w/o send rights"); ++ pthread_rwlock_unlock (&_ports_htable_lock); + return; + } + +-- +2.1.4 + diff --git a/debian/patches/0003-new-design.patch b/debian/patches/0003-new-design.patch new file mode 100644 index 00000000..2fde1825 --- /dev/null +++ b/debian/patches/0003-new-design.patch @@ -0,0 +1,452 @@ +From c9dce531c41baa55bdfd2cae22f2a029c7039f73 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Sat, 4 Apr 2015 13:22:30 +0200 +Subject: [PATCH hurd 3/4] new design + +--- + libports/Makefile | 2 +- + libports/create-bucket.c | 1 + + libports/destroy-right.c | 104 +-------------------------------- + libports/manage-multithread.c | 15 ++++- + libports/manage-one-thread.c | 4 ++ + libports/port-deref-deferred.c | 129 +++++++++++++++++++++++++++++++++++++++++ + libports/port-deref-deferred.h | 32 ++++++++++ + libports/ports.h | 7 +++ + 8 files changed, 189 insertions(+), 105 deletions(-) + create mode 100644 libports/port-deref-deferred.c + create mode 100644 libports/port-deref-deferred.h + +diff --git a/libports/Makefile b/libports/Makefile +index f49cb9f..b8b82ee 100644 +--- a/libports/Makefile ++++ b/libports/Makefile +@@ -36,7 +36,7 @@ SRCS = create-bucket.c create-class.c \ + interrupt-operation.c interrupt-on-notify.c interrupt-notified-rpcs.c \ + dead-name.c create-port.c import-port.c default-uninhibitable-rpcs.c \ + claim-right.c transfer-right.c create-port-noinstall.c create-internal.c \ +- interrupted.c extern-inline.c ++ interrupted.c extern-inline.c port-deref-deferred.c + + installhdrs = ports.h + +diff --git a/libports/create-bucket.c b/libports/create-bucket.c +index 2c5f1b6..32b2b76 100644 +--- a/libports/create-bucket.c ++++ b/libports/create-bucket.c +@@ -48,5 +48,6 @@ ports_create_bucket () + + hurd_ihash_init (&ret->htable, offsetof (struct port_info, hentry)); + ret->rpcs = ret->flags = ret->count = 0; ++ _ports_sync_init (&ret->sync); + return ret; + } +diff --git a/libports/destroy-right.c b/libports/destroy-right.c +index c229d77..a9a9702 100644 +--- a/libports/destroy-right.c ++++ b/libports/destroy-right.c +@@ -27,10 +27,6 @@ + #include <time.h> + #include <unistd.h> + +-/* To prevent protected payloads from becoming stale, we defer the +- derefercing of port_info objects. Consumes PI. */ +-static error_t defer_dereferencing (struct port_info *pi); +- + error_t + ports_destroy_right (void *portstruct) + { +@@ -67,7 +63,7 @@ ports_destroy_right (void *portstruct) + failure. However, stale payloads results in port_info + use-after-free. Therefore, we cannot release the + reference here, but defer that instead. */ +- defer_dereferencing (pi); ++ _ports_port_deref_deferred (pi); + } + + pi->port_right = MACH_PORT_DEAD; +@@ -76,101 +72,3 @@ ports_destroy_right (void *portstruct) + + return 0; + } +- +-/* Simple lock-less generational garbage collection. */ +- +-/* We maintain three lists of objects. Producers add objects to the +- current generation G using defer_dereferencing. G-1 holds old +- objects, G-2 holds garbage. */ +-static struct deferred_dereference +-{ +- struct deferred_dereference *next; +- struct port_info *pi; /* We hold a reference for these objects. */ +-} *generations[3]; /* Must be accessed using atomic +- operations. */ +- +-/* The current generation. Must be accessed using atomic operations. */ +-static int generation; +- +-/* The garbage collection thread. Does not return. */ +-static void * +-gc_loop (void *arg) +-{ +- while (1) +- { +- int old, garbage; +- struct deferred_dereference *d; +- +- sleep (5); +- +- /* We are the only one updating generation, so this is safe. */ +- old = generation; +- +- /* Update generation. */ +- __atomic_store_n (&generation, (old + 1) % 3, __ATOMIC_RELAXED); +- +- /* This is the garbage generation. As all writers are long +- gone, we do not need to bother with atomic operations. */ +- garbage = (old + 2) % 3; +- d = generations[garbage]; +- generations[garbage] = NULL; +- while (d != NULL) +- { +- struct deferred_dereference *next = d->next; +- +- /* Get rid of our reference. */ +- ports_port_deref (d->pi); +- +- free (d); +- d = next; +- } +- } +- +- assert (! "reached"); +- return NULL; +-} +- +-/* Start the gc thread. */ +-static void +-start_gc (void) +-{ +- error_t err; +- pthread_attr_t attr; +- pthread_t thread; +- +- pthread_attr_init (&attr); +-#define STACK_SIZE (64 * 1024) +- pthread_attr_setstacksize (&attr, STACK_SIZE); +-#undef STACK_SIZE +- +- err = pthread_create (&thread, &attr, gc_loop, NULL); +- assert_perror (err); +- err = pthread_detach (thread); +- assert_perror (err); +-} +- +-/* Defer the derefercing of port_info objects. Consumes PI. */ +-static error_t +-defer_dereferencing (struct port_info *pi) +-{ +- static pthread_once_t once = PTHREAD_ONCE_INIT; +- int g; +- struct deferred_dereference *d; +- pthread_once (&once, start_gc); +- +- d = malloc (sizeof *d); +- if (d == NULL) +- return ENOMEM; +- d->pi = pi; +- +- retry: +- /* Append to the current generation. */ +- g = __atomic_load_n (&generation, __ATOMIC_RELAXED); +- +- d->next = __atomic_load_n (&generations[g], __ATOMIC_RELAXED); +- if (! __atomic_compare_exchange_n (&generations[g], &d->next, d, +- 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) +- goto retry; +- +- return 0; +-} +diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c +index 9a5278e..a5952e8 100644 +--- a/libports/manage-multithread.c ++++ b/libports/manage-multithread.c +@@ -223,10 +223,19 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket, + void * + thread_function (void *arg) + { ++ struct ports_thread thread; + int master = (int) arg; + int timeout; + error_t err; + ++ int synchronized_demuxer (mach_msg_header_t *inp, ++ mach_msg_header_t *outheadp) ++ { ++ int r = internal_demuxer (inp, outheadp); ++ _ports_thread_quiescent (bucket, &thread); ++ return r; ++ } ++ + adjust_priority (__atomic_load_n (&totalthreads, __ATOMIC_RELAXED)); + + if (hook) +@@ -237,10 +246,13 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket, + else + timeout = thread_timeout; + ++ _ports_thread_online (bucket, &thread); ++ + startover: + + do +- err = mach_msg_server_timeout (internal_demuxer, 0, bucket->portset, ++ err = mach_msg_server_timeout (synchronized_demuxer, ++ 0, bucket->portset, + timeout ? MACH_RCV_TIMEOUT : 0, + timeout); + while (err != MACH_RCV_TIMED_OUT); +@@ -260,6 +272,7 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket, + } + __atomic_sub_fetch (&totalthreads, 1, __ATOMIC_RELAXED); + } ++ _ports_thread_offline (bucket, &thread); + return NULL; + } + +diff --git a/libports/manage-one-thread.c b/libports/manage-one-thread.c +index 58c0f36..0a8e4e7 100644 +--- a/libports/manage-one-thread.c ++++ b/libports/manage-one-thread.c +@@ -25,6 +25,7 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket, + ports_demuxer_type demuxer, + int timeout) + { ++ struct ports_thread thread; + error_t err; + + int +@@ -103,6 +104,7 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket, + status = 1; + } + ++ _ports_thread_quiescent (bucket, &thread); + return status; + } + +@@ -113,8 +115,10 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket, + zero. */ + timeout = 0; + ++ _ports_thread_online (bucket, &thread); + do + err = mach_msg_server_timeout (internal_demuxer, 0, bucket->portset, + timeout ? MACH_RCV_TIMEOUT : 0, timeout); + while (err != MACH_RCV_TIMED_OUT); ++ _ports_thread_offline (bucket, &thread); + } +diff --git a/libports/port-deref-deferred.c b/libports/port-deref-deferred.c +new file mode 100644 +index 0000000..27604c5 +--- /dev/null ++++ b/libports/port-deref-deferred.c +@@ -0,0 +1,129 @@ ++#include "ports.h" ++#include <assert.h> ++ ++#include <pthread.h> ++ ++#define COLOR_VALID(X) ((X) == COLOR_BLACK || (X) == COLOR_WHITE) ++ ++void ++_ports_sync_init (struct ports_sync *s) ++{ ++ pthread_spin_init (&s->lock, PTHREAD_PROCESS_PRIVATE); ++ s->color = COLOR_BLACK; ++ s->old_threads = 0; ++ s->old_objects = NULL; ++ s->young_threads = 0; ++ s->young_objects = NULL; ++} ++ ++static inline enum def_color ++flip_color (enum def_color c) ++{ ++ switch (c) ++ { ++ case COLOR_BLACK: ++ return COLOR_WHITE; ++ case COLOR_WHITE: ++ return COLOR_BLACK; ++ default: ++ assert (! "invalid color"); ++ } ++} ++ ++static inline void ++flip_generations (struct ports_sync *s) ++{ ++ assert (s->old_threads == 0); ++ s->old_threads = s->young_threads; ++ s->old_objects = s->young_objects; ++ s->young_threads = 0; ++ s->young_objects = NULL; ++ s->color = flip_color (s->color); ++} ++ ++void ++_ports_port_deref_deferred (struct port_info *pi) ++{ ++ struct ports_sync *s = &pi->bucket->sync; ++ ++ struct pi_list *pl = malloc (sizeof *pl); ++ if (pl == NULL) ++ return; ++ pl->pi = pi; ++ ++ pthread_spin_lock (&s->lock); ++ pl->next = s->young_objects; ++ s->young_objects = pl; ++ if (s->old_threads == 0) ++ { ++ assert (s->old_objects == NULL); ++ flip_generations (s); ++ } ++ pthread_spin_unlock (&s->lock); ++} ++ ++void ++_ports_thread_online (struct port_bucket *bucket, ++ struct ports_thread *t) ++{ ++ struct ports_sync *s = &bucket->sync; ++ pthread_spin_lock (&s->lock); ++ t->color = flip_color (s->color); ++ s->young_threads += 1; ++ pthread_spin_unlock (&s->lock); ++} ++ ++void ++_ports_thread_quiescent (struct port_bucket *bucket, ++ struct ports_thread *t) ++{ ++ struct ports_sync *s = &bucket->sync; ++ struct pi_list *free_list = NULL, *p; ++ assert (COLOR_VALID (t->color)); ++ ++ pthread_spin_lock (&s->lock); ++ if (t->color == s->color) ++ { ++ s->old_threads -= 1; ++ s->young_threads += 1; ++ t->color = flip_color (t->color); ++ ++ if (s->old_threads == 0) ++ { ++ free_list = s->old_objects; ++ flip_generations (s); ++ } ++ } ++ pthread_spin_unlock (&s->lock); ++ ++ if (free_list) ++ error (0, 0, "dereferencing %p, my color is %d", free_list, t->color); ++ ++ for (p = free_list; p;) ++ { ++ struct pi_list *old = p; ++ p = p->next; ++ ++ ports_port_deref (old->pi); ++ free (old); ++ } ++} ++ ++void ++_ports_thread_offline (struct port_bucket *bucket, ++ struct ports_thread *t) ++{ ++ struct ports_sync *s = &bucket->sync; ++ assert (COLOR_VALID (t->color)); ++ retry: ++ pthread_spin_lock (&s->lock); ++ if (t->color == s->color) ++ { ++ pthread_spin_unlock (&s->lock); ++ _ports_thread_quiescent (bucket, t); ++ goto retry; ++ } ++ t->color = COLOR_NONE; ++ s->young_threads -= 1; ++ pthread_spin_unlock (&s->lock); ++} +diff --git a/libports/port-deref-deferred.h b/libports/port-deref-deferred.h +new file mode 100644 +index 0000000..6586c81 +--- /dev/null ++++ b/libports/port-deref-deferred.h +@@ -0,0 +1,32 @@ ++#ifndef _HURD_PORTS_DEREF_DEFERRED_ ++#define _HURD_PORTS_DEREF_DEFERRED_ ++ ++enum def_color { COLOR_NONE, COLOR_BLACK, COLOR_WHITE }; ++ ++struct pi_list ++{ ++ struct pi_list *next; ++ struct port_info *pi; ++}; ++ ++struct ports_sync ++{ ++ pthread_spinlock_t lock; ++ ++ enum def_color color; ++ ++ size_t old_threads; ++ struct pi_list *old_objects; ++ ++ size_t young_threads; ++ struct pi_list *young_objects; ++}; ++ ++struct ports_thread ++{ ++ enum def_color color; ++}; ++ ++void _ports_sync_init (struct ports_sync *s); ++ ++#endif /* _HURD_PORTS_DEREF_DEFERRED_ */ +diff --git a/libports/ports.h b/libports/ports.h +index f02edb4..c047a1a 100644 +--- a/libports/ports.h ++++ b/libports/ports.h +@@ -29,6 +29,8 @@ + #include <pthread.h> + #include <refcount.h> + ++#include "port-deref-deferred.h" ++ + #ifdef PORTS_DEFINE_EI + #define PORTS_EI + #else +@@ -73,6 +75,7 @@ struct port_bucket + int rpcs; + int flags; + int count; ++ struct ports_sync sync; + }; + /* FLAGS above are the following: */ + #define PORT_BUCKET_INHIBITED PORTS_INHIBITED +@@ -477,4 +480,8 @@ void _ports_complete_deallocate (struct port_info *); + error_t _ports_create_port_internal (struct port_class *, struct port_bucket *, + size_t, void *, int); + ++void _ports_thread_online (struct port_bucket *, struct ports_thread *); ++void _ports_thread_quiescent (struct port_bucket *, struct ports_thread *); ++void _ports_thread_offline (struct port_bucket *, struct ports_thread *); ++ + #endif +-- +2.1.4 + diff --git a/debian/patches/0004-renamed-stuff.patch b/debian/patches/0004-renamed-stuff.patch new file mode 100644 index 00000000..e74633ed --- /dev/null +++ b/debian/patches/0004-renamed-stuff.patch @@ -0,0 +1,280 @@ +From f18e34a4a6cd93bad8af6e720f52c71b020c3f69 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Sat, 4 Apr 2015 13:57:30 +0200 +Subject: [PATCH hurd 4/4] renamed stuff + +--- + libports/create-bucket.c | 2 +- + libports/port-deref-deferred.c | 139 ++++++++++++++++++++++------------------- + libports/port-deref-deferred.h | 16 ++--- + libports/ports.h | 2 +- + 4 files changed, 82 insertions(+), 77 deletions(-) + +diff --git a/libports/create-bucket.c b/libports/create-bucket.c +index 32b2b76..82c00a4 100644 +--- a/libports/create-bucket.c ++++ b/libports/create-bucket.c +@@ -48,6 +48,6 @@ ports_create_bucket () + + hurd_ihash_init (&ret->htable, offsetof (struct port_info, hentry)); + ret->rpcs = ret->flags = ret->count = 0; +- _ports_sync_init (&ret->sync); ++ _ports_threadpool_init (&ret->threadpool); + return ret; + } +diff --git a/libports/port-deref-deferred.c b/libports/port-deref-deferred.c +index 27604c5..06b57f8 100644 +--- a/libports/port-deref-deferred.c ++++ b/libports/port-deref-deferred.c +@@ -3,101 +3,112 @@ + + #include <pthread.h> + +-#define COLOR_VALID(X) ((X) == COLOR_BLACK || (X) == COLOR_WHITE) ++/* ++ * A threadpool has a color indicating which threads belong to the old ++ * generation. ++ */ ++#define COLOR_BLACK 0 ++#define COLOR_WHITE 1 ++#define COLOR_INVALID ~0U ++ ++static inline int ++valid_color (unsigned int c) ++{ ++ return c == COLOR_BLACK || c == COLOR_WHITE; ++} + +-void +-_ports_sync_init (struct ports_sync *s) ++static inline unsigned int ++flip_color (unsigned int c) + { +- pthread_spin_init (&s->lock, PTHREAD_PROCESS_PRIVATE); +- s->color = COLOR_BLACK; +- s->old_threads = 0; +- s->old_objects = NULL; +- s->young_threads = 0; +- s->young_objects = NULL; ++ assert (valid_color (c)); ++ return ! c; + } + +-static inline enum def_color +-flip_color (enum def_color c) ++void ++_ports_threadpool_init (struct ports_threadpool *pool) + { +- switch (c) +- { +- case COLOR_BLACK: +- return COLOR_WHITE; +- case COLOR_WHITE: +- return COLOR_BLACK; +- default: +- assert (! "invalid color"); +- } ++ pthread_spin_init (&pool->lock, PTHREAD_PROCESS_PRIVATE); ++ pool->color = COLOR_BLACK; ++ pool->old_threads = 0; ++ pool->old_objects = NULL; ++ pool->young_threads = 0; ++ pool->young_objects = NULL; + } + + static inline void +-flip_generations (struct ports_sync *s) ++flip_generations (struct ports_threadpool *pool) + { +- assert (s->old_threads == 0); +- s->old_threads = s->young_threads; +- s->old_objects = s->young_objects; +- s->young_threads = 0; +- s->young_objects = NULL; +- s->color = flip_color (s->color); ++ assert (pool->old_threads == 0); ++ pool->old_threads = pool->young_threads; ++ pool->old_objects = pool->young_objects; ++ pool->young_threads = 0; ++ pool->young_objects = NULL; ++ pool->color = flip_color (pool->color); + } + ++struct pi_list ++{ ++ struct pi_list *next; ++ struct port_info *pi; ++}; ++ + void + _ports_port_deref_deferred (struct port_info *pi) + { +- struct ports_sync *s = &pi->bucket->sync; ++ struct ports_threadpool *pool = &pi->bucket->threadpool; + + struct pi_list *pl = malloc (sizeof *pl); + if (pl == NULL) + return; + pl->pi = pi; + +- pthread_spin_lock (&s->lock); +- pl->next = s->young_objects; +- s->young_objects = pl; +- if (s->old_threads == 0) ++ pthread_spin_lock (&pool->lock); ++ pl->next = pool->young_objects; ++ pool->young_objects = pl; ++ if (pool->old_threads == 0) + { +- assert (s->old_objects == NULL); +- flip_generations (s); ++ assert (pool->old_objects == NULL); ++ flip_generations (pool); + } +- pthread_spin_unlock (&s->lock); ++ pthread_spin_unlock (&pool->lock); + } + + void + _ports_thread_online (struct port_bucket *bucket, +- struct ports_thread *t) ++ struct ports_thread *thread) + { +- struct ports_sync *s = &bucket->sync; +- pthread_spin_lock (&s->lock); +- t->color = flip_color (s->color); +- s->young_threads += 1; +- pthread_spin_unlock (&s->lock); ++ struct ports_threadpool *pool = &bucket->threadpool; ++ pthread_spin_lock (&pool->lock); ++ thread->color = flip_color (pool->color); ++ pool->young_threads += 1; ++ pthread_spin_unlock (&pool->lock); + } + + void + _ports_thread_quiescent (struct port_bucket *bucket, +- struct ports_thread *t) ++ struct ports_thread *thread) + { +- struct ports_sync *s = &bucket->sync; ++ struct ports_threadpool *pool = &bucket->threadpool; + struct pi_list *free_list = NULL, *p; +- assert (COLOR_VALID (t->color)); ++ assert (valid_color (thread->color)); + +- pthread_spin_lock (&s->lock); +- if (t->color == s->color) ++ pthread_spin_lock (&pool->lock); ++ if (thread->color == pool->color) + { +- s->old_threads -= 1; +- s->young_threads += 1; +- t->color = flip_color (t->color); ++ pool->old_threads -= 1; ++ pool->young_threads += 1; ++ thread->color = flip_color (thread->color); + +- if (s->old_threads == 0) ++ if (pool->old_threads == 0) + { +- free_list = s->old_objects; +- flip_generations (s); ++ free_list = pool->old_objects; ++ flip_generations (pool); + } + } +- pthread_spin_unlock (&s->lock); ++ pthread_spin_unlock (&pool->lock); + + if (free_list) +- error (0, 0, "dereferencing %p, my color is %d", free_list, t->color); ++ error (0, 0, "dereferencing %p, my color is %d", free_list, thread->color); + + for (p = free_list; p;) + { +@@ -111,19 +122,19 @@ _ports_thread_quiescent (struct port_bucket *bucket, + + void + _ports_thread_offline (struct port_bucket *bucket, +- struct ports_thread *t) ++ struct ports_thread *thread) + { +- struct ports_sync *s = &bucket->sync; +- assert (COLOR_VALID (t->color)); ++ struct ports_threadpool *pool = &bucket->threadpool; ++ assert (valid_color (thread->color)); + retry: +- pthread_spin_lock (&s->lock); +- if (t->color == s->color) ++ pthread_spin_lock (&pool->lock); ++ if (thread->color == pool->color) + { +- pthread_spin_unlock (&s->lock); +- _ports_thread_quiescent (bucket, t); ++ pthread_spin_unlock (&pool->lock); ++ _ports_thread_quiescent (bucket, thread); + goto retry; + } +- t->color = COLOR_NONE; +- s->young_threads -= 1; +- pthread_spin_unlock (&s->lock); ++ thread->color = COLOR_INVALID; ++ pool->young_threads -= 1; ++ pthread_spin_unlock (&pool->lock); + } +diff --git a/libports/port-deref-deferred.h b/libports/port-deref-deferred.h +index 6586c81..6c208fd 100644 +--- a/libports/port-deref-deferred.h ++++ b/libports/port-deref-deferred.h +@@ -1,19 +1,13 @@ + #ifndef _HURD_PORTS_DEREF_DEFERRED_ + #define _HURD_PORTS_DEREF_DEFERRED_ + +-enum def_color { COLOR_NONE, COLOR_BLACK, COLOR_WHITE }; ++struct pi_list; + +-struct pi_list +-{ +- struct pi_list *next; +- struct port_info *pi; +-}; +- +-struct ports_sync ++struct ports_threadpool + { + pthread_spinlock_t lock; + +- enum def_color color; ++ unsigned int color; + + size_t old_threads; + struct pi_list *old_objects; +@@ -24,9 +18,9 @@ struct ports_sync + + struct ports_thread + { +- enum def_color color; ++ unsigned int color; + }; + +-void _ports_sync_init (struct ports_sync *s); ++void _ports_threadpool_init (struct ports_threadpool *); + + #endif /* _HURD_PORTS_DEREF_DEFERRED_ */ +diff --git a/libports/ports.h b/libports/ports.h +index c047a1a..dd396f2 100644 +--- a/libports/ports.h ++++ b/libports/ports.h +@@ -75,7 +75,7 @@ struct port_bucket + int rpcs; + int flags; + int count; +- struct ports_sync sync; ++ struct ports_threadpool threadpool; + }; + /* FLAGS above are the following: */ + #define PORT_BUCKET_INHIBITED PORTS_INHIBITED +-- +2.1.4 + diff --git a/debian/patches/series b/debian/patches/series index 49de301c..5d6f0e28 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -46,3 +46,7 @@ merge-me-0002-startup-faster-reboots.patch thomas_term.patch ajoin.patch proc_disable_new_task_notifications.patch +0001-libports-use-protected-payloads-to-optimize-the-obje.patch +0002-xxx-fix-and-assert-reached.patch +0003-new-design.patch +0004-renamed-stuff.patch |