diff options
Diffstat (limited to 'libports/ports.h')
-rw-r--r-- | libports/ports.h | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/libports/ports.h b/libports/ports.h new file mode 100644 index 00000000..ab347c84 --- /dev/null +++ b/libports/ports.h @@ -0,0 +1,405 @@ +/* Ports library for server construction + Copyright (C) 1993,94,95,96,97,99 Free Software Foundation, Inc. + Written by Michael I. Bushnell. + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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 <mach.h> +#include <stdlib.h> +#include <hurd.h> +#include <mach/notify.h> + +/* These are global values for common flags used in the various structures. + Not all of these are meaningful in all flag fields. */ +#define PORTS_INHIBITED 0x0100 /* block RPC's */ +#define PORTS_BLOCKED 0x0200 /* if INHIBITED, someone is blocked */ +#define PORTS_INHIBIT_WAIT 0x0400 /* someone wants to start inhibit */ +#define PORTS_NO_ALLOC 0x0800 /* block allocation */ +#define PORTS_ALLOC_WAIT 0x1000 /* someone wants to allocate */ + +struct port_info +{ + struct port_class *class; + int refcnt; + int weakrefcnt; + mach_port_mscount_t mscount; + mach_msg_seqno_t cancel_threshold; + int flags; + mach_port_t port_right; + struct rpc_info *current_rpcs; + struct port_bucket *bucket; + void **hentry; + struct port_info *next, **prevp; /* links on port_class list */ +}; +/* FLAGS above are the following: */ +#define PORT_HAS_SENDRIGHTS 0x0001 /* send rights extant */ +#define PORT_INHIBITED PORTS_INHIBITED +#define PORT_BLOCKED PORTS_BLOCKED +#define PORT_INHIBIT_WAIT PORTS_INHIBIT_WAIT + +struct port_bucket +{ + mach_port_t portset; + struct ihash *htable; + int rpcs; + int flags; + int count; + struct port_bucket *next; +}; +/* FLAGS above are the following: */ +#define PORT_BUCKET_INHIBITED PORTS_INHIBITED +#define PORT_BUCKET_BLOCKED PORTS_BLOCKED +#define PORT_BUCKET_INHIBIT_WAIT PORTS_INHIBIT_WAIT +#define PORT_BUCKET_NO_ALLOC PORTS_NO_ALLOC +#define PORT_BUCKET_ALLOC_WAIT PORTS_ALLOC_WAIT + +struct port_class +{ + int flags; + int rpcs; + struct port_info *ports; + int count; + void (*clean_routine) (void *); + void (*dropweak_routine) (void *); + struct ports_msg_id_range *uninhibitable_rpcs; +}; +/* FLAGS are the following: */ +#define PORT_CLASS_INHIBITED PORTS_INHIBITED +#define PORT_CLASS_BLOCKED PORTS_BLOCKED +#define PORT_CLASS_INHIBIT_WAIT PORTS_INHIBIT_WAIT +#define PORT_CLASS_NO_ALLOC PORTS_NO_ALLOC +#define PORT_CLASS_ALLOC_WAIT PORTS_ALLOC_WAIT + +struct rpc_info +{ + thread_t thread; + struct rpc_info *next, **prevp; + struct rpc_notify *notifies; + struct rpc_info *interrupted_next; +}; + +/* An rpc has requested interruption on a port notification. */ +struct rpc_notify +{ + struct rpc_info *rpc; /* Which rpc this is for. */ + struct ports_notify *notify; /* Which port/request this refers too. */ + + struct rpc_notify *next; /* Notify for this rpc. */ + unsigned pending; /* Number of requests this represents. */ + + struct rpc_notify *next_req; /* rpc for this notify. */ + struct rpc_notify **prev_req_p; /* who points to this rpc_notify. */ +}; + +/* A notification request on a (not necessarily registered) port. */ +struct ports_notify +{ + mach_port_t port; /* */ + mach_msg_id_t what; /* MACH_NOTIFY_* */ + unsigned pending : 1; /* There's a notification outstanding. */ + struct mutex lock; + + struct rpc_notify *reqs; /* Which rpcs are notified by this port. */ + struct ports_notify *next, **prevp; /* Linked list of all notified ports. */ +}; + +/* A linked list of ports that have had notification requested. */ +extern struct ports_notify *_ports_notifications; + +/* Free lists for notify structures. */ +extern struct ports_notify *_ports_free_ports_notifies; +extern struct rpc_notify *_ports_free_rpc_notifies; + +/* Remove RPC from the list of notified rpcs, cancelling any pending + notifications. _PORTS_LOCK should be held. */ +void _ports_remove_notified_rpc (struct rpc_info *rpc); + +struct ports_msg_id_range +{ + mach_msg_id_t start, end; + struct ports_msg_id_range *next; +}; + +/* This is the initial value for the uninhibitable_rpcs field in new + port_class structures. The user may define this variable; the default + value contains only an entry for interrupt_operation. */ +extern struct ports_msg_id_range *ports_default_uninhibitable_rpcs; + +/* Port creation and port right frobbing */ + +/* Create and return a new bucket. */ +struct port_bucket *ports_create_bucket (void); + +/* Create and return a new port class. If nonzero, CLEAN_ROUTINE will + be called for each allocated port object in this class when it is + being destroyed. If nonzero, DROPWEAK_ROUTINE will be called + to request weak references to be dropped. (If DROPWEAK_ROUTINE is null, + then normal references and hard references will be identical for + ports of this class.) */ +struct port_class *ports_create_class (void (*clean_routine)(void *), + void (*dropweak_routine)(void *)); + +/* Create and return in RESULT a new port in CLASS and BUCKET; SIZE bytes + will be allocated to hold the port structure and whatever private data the + user desires. */ +error_t ports_create_port (struct port_class *class, + struct port_bucket *bucket, + size_t size, + void *result); + +/* Just like ports_create_port, except don't actually put the port + into the portset underlying BUCKET. This is intended to be used + for cases where the port right must be given out before the port is + fully initialized; with this call you are guaranteed that no RPC + service will occur on the port until you have finished initializing + it and installed it into the portset yourself. */ +error_t +ports_create_port_noinstall (struct port_class *class, + struct port_bucket *bucket, + size_t size, + void *result); + +/* For an existing RECEIVE right, create and return in RESULT a new port + structure; BUCKET, SIZE, and CLASS args are as for ports_create_port. */ +error_t ports_import_port (struct port_class *class, + struct port_bucket *bucket, + mach_port_t port, size_t size, + void *result); + +/* Destroy the receive right currently associated with PORT and allocate + a new one. */ +void ports_reallocate_port (void *port); + +/* Destroy the receive right currently associated with PORT and designate + RECEIVE as the new one. */ +void ports_reallocate_from_external (void *port, mach_port_t receive); + +/* Destroy the receive right currently associated with PORT. After + this call, ports_reallocate_port and ports_reallocate_from_external + may not be used. Always returns 0, for convenient use as an iterator. */ +error_t ports_destroy_right (void *port); + +/* Return the receive right currently associated with PORT. The effects + on PORT are the same as in ports_destroy_right, except that the receive + right itself is not affected. Note that in multi-threaded servers, + messages might already have been dequeued for this port before it gets + removed from the portset; such messages will get EOPNOTSUPP errors. */ +mach_port_t ports_claim_right (void *port); + +/* Transfer the receive right from FROMPT to TOPT. FROMPT ends up + with a destroyed right (as if ports_destroy_right were called) and + TOPT's old right is destroyed (as if ports_reallocate_from_external + were called. */ +error_t ports_transfer_right (void *topt, void *frompt); + +/* Return the name of the receive right associated with PORT. The user + is responsible for creating an ordinary send right from this name. */ +mach_port_t ports_get_right (void *port); + + + +/* Reference counting */ + +/* Look up PORT and return the associated port structure, allocating a + reference. If the call fails, return 0. If BUCKET is nonzero, + then it specifies a bucket to search; otherwise all buckets will be + searched. If CLASS is nonzero, then the lookup will fail if PORT + is not in CLASS. */ +void *ports_lookup_port (struct port_bucket *bucket, + mach_port_t port, struct port_class *class); + +/* Allocate another reference to PORT. */ +void ports_port_ref (void *port); + +/* Allocate a weak reference to PORT. */ +void ports_port_ref_weak (void *port); + +/* Drop a reference to PORT. */ +void ports_port_deref (void *port); + +/* Drop a weak reference to PORT. */ +void ports_port_deref_weak (void *port); + +/* The user is responsible for listening for no senders notifications; + when one arrives, call this routine for the PORT the message was + sent to, providing the MSCOUNT from the notification. */ +void ports_no_senders (void *port, mach_port_mscount_t mscount); +void ports_dead_name (void *notify, mach_port_t dead_name); + +/* Block port creation of new ports in CLASS. Return the number + of ports currently in CLASS. */ +int ports_count_class (struct port_class *class); + +/* Block port creation of new ports in BUCKET. Return the number + of ports currently in BUCKET. */ +int ports_count_bucket (struct port_bucket *bucket); + +/* Permit suspended port creation (blocked by ports_count_class) + to continue. */ +void ports_enable_class (struct port_class *class); + +/* Permit suspend port creation (blocked by ports_count_bucket) + to continue. */ +void ports_enable_bucket (struct port_bucket *bucket); + +/* Call FUN once for each port in BUCKET. */ +error_t ports_bucket_iterate (struct port_bucket *bucket, + error_t (*fun)(void *port)); + +/* Call FUN once for each port in CLASS. */ +error_t ports_class_iterate (struct port_class *class, + error_t (*fun)(void *port)); + +/* Internal entrypoint for above two. */ +error_t _ports_bucket_class_iterate (struct port_bucket *bucket, + struct port_class *class, + error_t (*fun)(void *port)); + +/* RPC management */ + +/* Type of MiG demuxer routines. */ +typedef int (*ports_demuxer_type)(mach_msg_header_t *inp, + mach_msg_header_t *outp); + +/* Call this when an RPC is beginning on PORT. INFO should be + allocated by the caller and will be used to hold dynamic state. + If this RPC should be abandoned, return EDIED; otherwise we + return zero. */ +error_t ports_begin_rpc (void *port, mach_msg_id_t msg_id, + struct rpc_info *info); + +/* Call this when an RPC is concluding. Args must be as for the + paired call to ports_begin_rpc. */ +void ports_end_rpc (void *port, struct rpc_info *info); + +/* Begin handling operations for the ports in BUCKET, calling DEMUXER + for each incoming message. Return if TIMEOUT is nonzero and no + messages have been received for TIMEOUT milliseconds. Use + only one thread (the calling thread). */ +void ports_manage_port_operations_one_thread(struct port_bucket *bucket, + ports_demuxer_type demuxer, + int timeout); + +/* Begin handling operations for the ports in BUCKET, calling DEMUXER + for each incoming message. Return if GLOBAL_TIMEOUT is nonzero and + no messages have been receieved for GLOBAL_TIMEOUT milliseconds. + Create threads as necessary to handle incoming messages so that no + port is starved because of sluggishness on another port. If + LOCAL_TIMEOUT is non-zero, then individual threads will die off if + they handle no incoming messages for LOCAL_TIMEOUT milliseconds. + HOOK (if not null) will be called in each new thread immediately + after it is created. */ +void ports_manage_port_operations_multithread (struct port_bucket *bucket, + ports_demuxer_type demuxer, + int thread_timeout, + int global_timeout, + void (*hook)(void)); + +/* Interrupt any pending RPC on PORT. Wait for all pending RPC's to + finish, and then block any new RPC's starting on that port. */ +error_t ports_inhibit_port_rpcs (void *port); + +/* Similar to ports_inhibit_port_rpcs, but affects all ports in CLASS. */ +error_t ports_inhibit_class_rpcs (struct port_class *class); + +/* Similar to ports_inhibit_port_rpcs, but affects all ports in BUCKET. */ +error_t ports_inhibit_bucket_rpcs (struct port_bucket *bucket); + +/* Similar to ports_inhibit_port_rpcs, but affects all ports whatsoever. */ +error_t ports_inhibit_all_rpcs (void); + +/* Reverse the effect of a previous ports_inhibit_port_rpcs for this PORT, + allowing blocked RPC's to continue. */ +void ports_resume_port_rpcs (void *port); + +/* Reverse the effect of a previous ports_inhibit_class_rpcs for CLASS. */ +void ports_resume_class_rpcs (struct port_class *class); + +/* Reverse the effect of a previous ports_inhibit_bucket_rpcs for BUCKET. */ +void ports_resume_bucket_rpcs (struct port_bucket *bucket); + +/* Reverse the effect of a previous ports_inhibit_all_rpcs. */ +void ports_resume_all_rpcs (void); + +/* Cancel (with thread_cancel) any RPC's in progress on PORT. */ +void ports_interrupt_rpcs (void *port); + +/* If the current thread's rpc has been interrupted with + ports_interrupt_rpcs, return true (and clear the interrupted flag). */ +int ports_self_interrupted (); + +/* Add RPC to the list of rpcs that have been interrupted. */ +void _ports_record_interruption (struct rpc_info *rpc); + +/* Arrange for hurd_cancel to be called on RPC's thread if OBJECT gets notified + that any of the things in COND have happened to PORT. RPC should be an + rpc on OBJECT. */ +error_t +ports_interrupt_rpc_on_notification (void *object, + struct rpc_info *rpc, + mach_port_t port, mach_msg_id_t what); + +/* Arrange for hurd_cancel to be called on the current thread, which should + be an rpc on OBJECT, if PORT gets notified with the condition WHAT. */ +error_t +ports_interrupt_self_on_notification (void *object, + mach_port_t port, mach_msg_id_t what); + +/* Some handy aliases. */ +#define ports_interrupt_self_on_port_death(obj, port) \ + ports_interrupt_self_on_notification (obj, port, MACH_NOTIFY_DEAD_NAME) + +/* Interrupt any rpcs on OBJECT that have requested such. */ +void ports_interrupt_notified_rpcs (void *object, mach_port_t port, + mach_msg_id_t what); + +/* Default servers */ + +/* A notification server that calls the ports_do_mach_notify_* routines. */ +int ports_notify_server (mach_msg_header_t *, mach_msg_header_t *); + +/* Notification server routines called by ports_notify_server. */ +extern kern_return_t ports_do_mach_notify_dead_name (mach_port_t notify, mach_port_t deadport); +extern kern_return_t ports_do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name); +extern kern_return_t ports_do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t count); +extern kern_return_t ports_do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name); +extern kern_return_t ports_do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name); +extern kern_return_t + ports_do_mach_notify_send_once (mach_port_t notify); + +/* A default interrupt server */ +int ports_interrupt_server (mach_msg_header_t *, mach_msg_header_t *); +extern kern_return_t ports_S_interrupt_operation (mach_port_t, + mach_port_seqno_t); + +/* Private data */ +extern struct mutex _ports_lock; +extern struct condition _ports_block; +extern struct port_bucket *_ports_all_buckets; +extern int _ports_total_rpcs; +extern int _ports_flags; +#define _PORTS_INHIBITED PORTS_INHIBITED +#define _PORTS_BLOCKED PORTS_BLOCKED +#define _PORTS_INHIBIT_WAIT PORTS_INHIBIT_WAIT +void _ports_complete_deallocate (struct port_info *); +error_t _ports_create_port_internal (struct port_class *, struct port_bucket *, + size_t, void *, int); + +#endif |