diff options
Diffstat (limited to 'debian/patches/0003-new-design.patch')
-rw-r--r-- | debian/patches/0003-new-design.patch | 452 |
1 files changed, 452 insertions, 0 deletions
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 + |