Back to index

glibc  2.9
port.h
Go to the documentation of this file.
00001 /* Lightweight user references for ports.
00002    Copyright (C) 1993, 1994, 1995, 1997, 1999, 2007
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #ifndef       _HURD_PORT_H
00022 
00023 #define       _HURD_PORT_H  1
00024 #include <features.h>
00025 
00026 #include <mach.h>
00027 #include <hurd/userlink.h>
00028 #include <spin-lock.h>
00029 #include <hurd/signal.h>
00030 
00031 
00032 /* Structure describing a cell containing a port.  With the lock held, a
00033    user extracts PORT, and attaches his own link (in local storage) to the
00034    USERS chain.  PORT can then safely be used.  When PORT is no longer
00035    needed, with the lock held, the user removes his link from the chain.
00036    If his link is the last, and PORT has changed since he fetched it, the
00037    user deallocates the port he used.  See <hurd/userlink.h>.  */
00038 
00039 struct hurd_port
00040   {
00041     spin_lock_t lock;              /* Locks rest.  */
00042     struct hurd_userlink *users; /* Chain of users; see below.  */
00043     mach_port_t port;              /* Port. */
00044   };
00045 
00046 
00047 /* Evaluate EXPR with the variable `port' bound to the port in PORTCELL.  */
00048 
00049 #define       HURD_PORT_USE(portcell, expr)                                        \
00050   ({ struct hurd_port *const __p = (portcell);                              \
00051      struct hurd_userlink __link;                                    \
00052      const mach_port_t port = _hurd_port_get (__p, &__link);                \
00053      __typeof(expr) __result = (expr);                                      \
00054      _hurd_port_free (__p, &__link, port);                                  \
00055      __result; })
00056 
00057 
00058 #ifndef _HURD_PORT_H_EXTERN_INLINE
00059 #define _HURD_PORT_H_EXTERN_INLINE __extern_inline
00060 #endif
00061 
00062 
00063 /* Initialize *PORT to INIT.  */
00064 
00065 _HURD_PORT_H_EXTERN_INLINE void
00066 _hurd_port_init (struct hurd_port *port, mach_port_t init)
00067 {
00068   __spin_lock_init (&port->lock);
00069   port->users = NULL;
00070   port->port = init;
00071 }
00072 
00073 
00074 /* Cleanup function for non-local exits.  */
00075 extern void _hurd_port_cleanup (void *, jmp_buf, int);
00076 
00077 /* Get a reference to *PORT, which is locked.
00078    Pass return value and LINK to _hurd_port_free when done.  */
00079 
00080 _HURD_PORT_H_EXTERN_INLINE mach_port_t
00081 _hurd_port_locked_get (struct hurd_port *port,
00082                      struct hurd_userlink *link)
00083 {
00084   mach_port_t result;
00085   result = port->port;
00086   if (result != MACH_PORT_NULL)
00087     {
00088       link->cleanup = &_hurd_port_cleanup;
00089       link->cleanup_data = (void *) result;
00090       _hurd_userlink_link (&port->users, link);
00091     }
00092   __spin_unlock (&port->lock);
00093   return result;
00094 }
00095 
00096 /* Same, but locks PORT first.  */
00097 
00098 _HURD_PORT_H_EXTERN_INLINE mach_port_t
00099 _hurd_port_get (struct hurd_port *port,
00100               struct hurd_userlink *link)
00101 {
00102   mach_port_t result;
00103   HURD_CRITICAL_BEGIN;
00104   __spin_lock (&port->lock);
00105   result = _hurd_port_locked_get (port, link);
00106   HURD_CRITICAL_END;
00107   return result;
00108 }
00109 
00110 
00111 /* Free a reference gotten with `USED_PORT = _hurd_port_get (PORT, LINK);' */
00112 
00113 _HURD_PORT_H_EXTERN_INLINE void
00114 _hurd_port_free (struct hurd_port *port,
00115                struct hurd_userlink *link,
00116                mach_port_t used_port)
00117 {
00118   int dealloc;
00119   if (used_port == MACH_PORT_NULL)
00120     /* When we fetch an empty port cell with _hurd_port_get,
00121        it does not link us on the users chain, since there is
00122        no shared resource.  */
00123     return;
00124   HURD_CRITICAL_BEGIN;
00125   __spin_lock (&port->lock);
00126   dealloc = _hurd_userlink_unlink (link);
00127   __spin_unlock (&port->lock);
00128   HURD_CRITICAL_END;
00129   if (dealloc)
00130     __mach_port_deallocate (__mach_task_self (), used_port);
00131 }
00132 
00133 
00134 /* Set *PORT's port to NEWPORT.  NEWPORT's reference is consumed by PORT->port.
00135    PORT->lock is locked.  */
00136 
00137 _HURD_PORT_H_EXTERN_INLINE void
00138 _hurd_port_locked_set (struct hurd_port *port, mach_port_t newport)
00139 {
00140   mach_port_t old;
00141   old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL;
00142   port->port = newport;
00143   __spin_unlock (&port->lock);
00144   if (old != MACH_PORT_NULL)
00145     __mach_port_deallocate (__mach_task_self (), old);
00146 }
00147 
00148 /* Same, but locks PORT first.  */
00149 
00150 _HURD_PORT_H_EXTERN_INLINE void
00151 _hurd_port_set (struct hurd_port *port, mach_port_t newport)
00152 {
00153   HURD_CRITICAL_BEGIN;
00154   __spin_lock (&port->lock);
00155   _hurd_port_locked_set (port, newport);
00156   HURD_CRITICAL_END;
00157 }
00158 
00159 
00160 #endif /* hurd/port.h */