summaryrefslogtreecommitdiff
path: root/debian/patches/0003-new-design.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0003-new-design.patch')
-rw-r--r--debian/patches/0003-new-design.patch452
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
+