/* Definitions for multi-threaded server port management library
   Copyright (C) 1993, 1994 Free Software Foundation

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program 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
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#ifndef _HURD_PORTS_
#define _HURD_PORTS_

#include <stdlib.h>
#include <mach.h>
#include <spin-lock.h>

struct port_info
{
  int type;
  int refcnt;
  int mscount;
  int sendrights;
  int soft;
  mach_port_t port_right;	/* receive right */
};


/* Call this routine to allocate a port.  Your structure should
   begin with a struct port_info, and the SIZE should be for the combined
   structure.  If all you care about is the type, you can just use
   struct port_info itself.  The port will be (by default) a hard port.  */
void *ports_allocate_port (size_t SIZE, int TYPE);

/* Create a port structure for an externally generated port.  It is
   nearly always better to use ports_allocate_port, but if you are
   forced to deal with a receive right that some other agent gave you,
   you can use this routine. */
void *ports_intern_external_port (mach_port_t RECEIVE, size_t SIZE, int TYPE);

/* Change the hard/soft characteristic of port PORT; if SOFT is
   nonzero, designate the port as soft, otherwise designate it as
   hard. */
void ports_change_hardsoft (void *port, int soft);

/* This routine destroys the existing receive right and allocates
   a new one.  Any existing send rights in this task for the receive right
   remain, as dead-name rights. */
void ports_reallocate_port (void *);

/* Check to see if PORT was created by a previous call to allocate_port;
   if it was, check also to see if it is the proper type.  If either
   test fails, return 0, otherwise, return the port structure.  This
   call must be matched with a call to done_with_port; the port will
   be protected from cleaning between the two. */
void *ports_check_port_type (mach_port_t PORT, int TYPE);

/* Like check_port_type, but doesn't check against type. */
void *ports_get_port (mach_port_t PORT);

/* Acquire a reference to a port structure. */
void ports_port_ref (void *);

/* Return a receive right for port_info PI.  It is assumed that
   exactly one send right will be created from this right.  */
mach_port_t ports_get_right (void *PI);

/* Call this when done with a sequence of operations that began with
   check_port_type; also call this when a dead name notification
   is received on the port. */
void ports_done_with_port (void *);

/* Call this when a no-senders notification is received on port_info
   PI; MSCOUNT should be the mscount from the message. */
void ports_no_senders (void *pi, mach_port_mscount_t mscount);

/* Begin handling requests for ports created with allocate_port,
   calling the specified demux function.  The demux function should
   be able to deal with dead name notifications, and call done_with_port
   for them.  This function will run requests in parallel as much
   as possible, wiring those threads if ports_wire_threads is set.*/
void ports_manage_port_operations_multithread (void);

/* Just like ports_manage_port_operations_multithread, except only
   use one thread. */
void ports_manage_port_operations_onethread (void);

/* We provide a hash table mechanism, but it can be overridden by
   users who don't like the provided one, by defining the functions 
   below. */
void _libports_hash_intern (struct port_info *);
void _libports_hash_remove (struct port_info *);
struct port_info *_libports_hash_lookup (mach_port_t);

/* The user must define this function. */
int ports_demuxer(mach_msg_header_t *, mach_msg_header_t *);

/* The user must define this function.  This will be called whenever
   there have been no requests to the server for a significant period
   of time.  NHARD is the number of live hard ports; NSOFT is the
   number of live soft ports.  This function is called while an
   internal lock is held, so it cannot reliably call any other
   functions of the ports library. */
void ports_notice_idle (int nhard, int nsoft);

/* The user must define this function.  This will be called whenever
   there are no hard ports or soft ports allocated.  This function is
   called while an internal lock is held, so it cannot reliably call
   any other functions of the ports library. */
void ports_no_live_ports ();

/* The user must define this function.  This will be called whenever
   there are no hard ports allocated but there are still some soft
   ports.  This function is called while an internal lock is held, so
   it cannot reliably call any other functions of the ports
   library. */
void ports_no_hard_ports ();

/* If this function is declared, it gets called after the 
   type-specific clean routine for each cleaned port. */
void (*ports_generic_cleanroutine)(void *);

/* If this variable is defined by the user as non-zero, then
   call thread_wire for all threads we create.  It should be
   a send right for the master host port.*/
mach_port_t ports_wire_threads;

/* If this variable is defined by the user as non-zero, then
   call cthread_wire for all threads we create. */
int ports_wire_cthreads;

/* The user must declare this array, indexed by the possible port types. */
extern void (*ports_cleanroutines[])(void *);

/* Private data used by port management routines. */
extern mach_port_t _libports_request_portset;
extern spin_lock_t _libports_portrefcntlock;
extern spin_lock_t _ports_mscount_lock;
extern spin_lock_t _ports_count_lock;
extern int _ports_nhardports;
extern int _ports_nsoftports;
#endif
