diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2013-11-23 16:12:55 +0100 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-07 14:23:36 +0200 |
commit | 4241dd5673566a61add85bd9eb52d4ae7db2750a (patch) | |
tree | 0c7ce8514067068a877d8181544c2870af1dac7d /libports/destroy-right.c | |
parent | 785f4aea18b5705e63609001d2aa12871a774804 (diff) |
libports: use protected payloads to optimize the object lookup
* NEWS: Mention protected payloads.
* libports/Makefile (SRCS): Add `port-deref-deferred.c'.
* 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 for the object lookup if provided. Add
thread pool management calls.
* 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.
* libports/port-deref-deferred.c: New file.
* libports/port-deref-deferred.h: Likewise.
* libports/ports.h (struct port_bucket): New field `threadpool'.
(ports_lookup_payload): Check `port_right'.
Diffstat (limited to 'libports/destroy-right.c')
-rw-r--r-- | libports/destroy-right.c | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/libports/destroy-right.c b/libports/destroy-right.c index 448b3798..276255f4 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,62 @@ #include <hurd/ihash.h> #include <assert.h> +#include <pthread.h> +#include <error.h> +#include <time.h> +#include <unistd.h> + error_t ports_destroy_right (void *portstruct) { struct port_info *pi = portstruct; + mach_port_t port_right; + int defer = 0; error_t err; - if (pi->port_right != MACH_PORT_NULL) + pthread_mutex_lock (&_ports_lock); + port_right = pi->port_right; + pi->port_right = MACH_PORT_DEAD; + + if (pi->flags & PORT_HAS_SENDRIGHTS) + { + pi->flags &= ~PORT_HAS_SENDRIGHTS; + + /* There are outstanding send rights, so we might get more + messages. Attached to the messages 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 dequeued to userspace. + + 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 until all currently running threads have gone + through a quiescent state. */ + defer = 1; + } + + if (MACH_PORT_VALID (port_right)) { + mach_port_clear_protected_payload (mach_task_self (), port_right); + 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; + } + pthread_mutex_unlock (&_ports_lock); - if (pi->flags & PORT_HAS_SENDRIGHTS) - { - pi->flags &= ~PORT_HAS_SENDRIGHTS; - ports_port_deref (pi); - } + if (MACH_PORT_VALID (port_right)) + { + err = mach_port_mod_refs (mach_task_self (), port_right, + MACH_PORT_RIGHT_RECEIVE, -1); + assert_perror (err); } + if (defer) + _ports_port_deref_deferred (pi); + return 0; } |