| /* Lightweight user references for ports. |
| Copyright (C) 1993-2014 Free Software Foundation, Inc. |
| This file is part of the GNU C Library. |
| |
| The GNU C Library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| The GNU C Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef _HURD_PORT_H |
| |
| #define _HURD_PORT_H 1 |
| #include <features.h> |
| |
| #include <mach.h> |
| #include <hurd/userlink.h> |
| #include <spin-lock.h> |
| #include <hurd/signal.h> |
| |
| |
| /* Structure describing a cell containing a port. With the lock held, a |
| user extracts PORT, and attaches his own link (in local storage) to the |
| USERS chain. PORT can then safely be used. When PORT is no longer |
| needed, with the lock held, the user removes his link from the chain. |
| If his link is the last, and PORT has changed since he fetched it, the |
| user deallocates the port he used. See <hurd/userlink.h>. */ |
| |
| struct hurd_port |
| { |
| spin_lock_t lock; /* Locks rest. */ |
| struct hurd_userlink *users; /* Chain of users; see below. */ |
| mach_port_t port; /* Port. */ |
| }; |
| |
| |
| /* Evaluate EXPR with the variable `port' bound to the port in PORTCELL. */ |
| |
| #define HURD_PORT_USE(portcell, expr) \ |
| ({ struct hurd_port *const __p = (portcell); \ |
| struct hurd_userlink __link; \ |
| const mach_port_t port = _hurd_port_get (__p, &__link); \ |
| __typeof(expr) __result = (expr); \ |
| _hurd_port_free (__p, &__link, port); \ |
| __result; }) |
| |
| |
| #ifndef _HURD_PORT_H_EXTERN_INLINE |
| #define _HURD_PORT_H_EXTERN_INLINE __extern_inline |
| #endif |
| |
| |
| /* Initialize *PORT to INIT. */ |
| |
| _HURD_PORT_H_EXTERN_INLINE void |
| _hurd_port_init (struct hurd_port *port, mach_port_t init) |
| { |
| __spin_lock_init (&port->lock); |
| port->users = NULL; |
| port->port = init; |
| } |
| |
| |
| /* Cleanup function for non-local exits. */ |
| extern void _hurd_port_cleanup (void *, jmp_buf, int); |
| |
| /* Get a reference to *PORT, which is locked. |
| Pass return value and LINK to _hurd_port_free when done. */ |
| |
| _HURD_PORT_H_EXTERN_INLINE mach_port_t |
| _hurd_port_locked_get (struct hurd_port *port, |
| struct hurd_userlink *link) |
| { |
| mach_port_t result; |
| result = port->port; |
| if (result != MACH_PORT_NULL) |
| { |
| link->cleanup = &_hurd_port_cleanup; |
| link->cleanup_data = (void *) result; |
| _hurd_userlink_link (&port->users, link); |
| } |
| __spin_unlock (&port->lock); |
| return result; |
| } |
| |
| /* Same, but locks PORT first. */ |
| |
| _HURD_PORT_H_EXTERN_INLINE mach_port_t |
| _hurd_port_get (struct hurd_port *port, |
| struct hurd_userlink *link) |
| { |
| mach_port_t result; |
| HURD_CRITICAL_BEGIN; |
| __spin_lock (&port->lock); |
| result = _hurd_port_locked_get (port, link); |
| HURD_CRITICAL_END; |
| return result; |
| } |
| |
| |
| /* Free a reference gotten with `USED_PORT = _hurd_port_get (PORT, LINK);' */ |
| |
| _HURD_PORT_H_EXTERN_INLINE void |
| _hurd_port_free (struct hurd_port *port, |
| struct hurd_userlink *link, |
| mach_port_t used_port) |
| { |
| int dealloc; |
| if (used_port == MACH_PORT_NULL) |
| /* When we fetch an empty port cell with _hurd_port_get, |
| it does not link us on the users chain, since there is |
| no shared resource. */ |
| return; |
| HURD_CRITICAL_BEGIN; |
| __spin_lock (&port->lock); |
| dealloc = _hurd_userlink_unlink (link); |
| __spin_unlock (&port->lock); |
| HURD_CRITICAL_END; |
| if (dealloc) |
| __mach_port_deallocate (__mach_task_self (), used_port); |
| } |
| |
| |
| /* Set *PORT's port to NEWPORT. NEWPORT's reference is consumed by PORT->port. |
| PORT->lock is locked. */ |
| |
| _HURD_PORT_H_EXTERN_INLINE void |
| _hurd_port_locked_set (struct hurd_port *port, mach_port_t newport) |
| { |
| mach_port_t old; |
| old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL; |
| port->port = newport; |
| __spin_unlock (&port->lock); |
| if (old != MACH_PORT_NULL) |
| __mach_port_deallocate (__mach_task_self (), old); |
| } |
| |
| /* Same, but locks PORT first. */ |
| |
| _HURD_PORT_H_EXTERN_INLINE void |
| _hurd_port_set (struct hurd_port *port, mach_port_t newport) |
| { |
| HURD_CRITICAL_BEGIN; |
| __spin_lock (&port->lock); |
| _hurd_port_locked_set (port, newport); |
| HURD_CRITICAL_END; |
| } |
| |
| |
| #endif /* hurd/port.h */ |