Blame hurd/hurd/port.h

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