Every Hurd program accepts the following optional arguments:
Display a brief usage message, then exit. This message is not a substitute for reading program documentation; rather, it provides useful reminders about specific command-line options that a program understands.
Output program version information and exit.
The rest of this chapter provides a programmer’s introduction to the Hurd. If you are not a programmer, then this chapter will not make much sense to you… you should consider skipping to descriptions of specific Hurd programs (see Audience).
The Hurd distribution includes many libraries in order to provide a useful set of tools for writing Hurd utilities and servers. Several of these libraries are useful not only for the Hurd, but also for writing microkernel-based programs in general. These fundamental libraries are not difficult to understand, and they are a good starting point, because the rest of the Hurd relies upon them quite heavily.
All Hurd servers and libraries are aggressively multithreaded in order
to take full advantage of any multiprocessing capabilities provided by
the microkernel and the underlying hardware. The Hurd threads library,
libpthread
, contains the default Hurd thread implementation, which
is declared in <pthread.h>
.
The Hurd uses POSIX pthreads, which are documented in a lot of places.
Every single library in the Hurd distribution (including the GNU C library) is completely thread-safe, and the Hurd servers themselves are aggressively multithreaded.
Ports are communication channels that are held by the kernel.
A port has separate send rights and receive rights, which may be transferred from task to task via the kernel. Port rights are similar to Unix file descriptors: they are per-task integers which are used to identify ports when making kernel calls. Send rights are required in order to send an RPC request down a port, and receive rights are required to serve the RPC request. Receive rights may be aggregated into a single portset, which serve as useful organizational units.
In a single-threaded RPC client, managing and categorizing ports is not a difficult process. However, in a complex multithreaded server, it is useful to have a more abstract interface to managing portsets, as well as maintaining server metadata.
The Hurd ports library, libports
, fills that need. The
libports
functions are declared in <hurd/ports.h>
.
The libports
bucket is simply a port set, with some
metadata and a lock. All of the libports
functions operate on
buckets.
struct port_bucket *
ports_create_bucket (void)
¶Create and return a new, empty bucket.
A port class is a collection of individual ports, which can be manipulated conveniently, and have enforced deallocation routines. Buckets and classes are entirely orthogonal: there is no requirement that all the ports in a class be in the same bucket, nor is there a requirement that all the ports in a bucket be in the same class.
struct port_class
ports_create_class (void (*clean_routine) (void *port), void (*dropweak_routine) (void *port))
¶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 weak references and hard references will be identical for ports of this class.)
Once you have created at least one bucket and class, you may create new ports, and store them in those buckets. There are a few different functions for port creation, depending on your application’s requirements:
error_t
ports_create_port (struct port_class *class, struct port_bucket *bucket, size_t size, void *result)
¶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_noinstall (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_import_port (struct port_class *class, struct port_bucket *bucket, mach_port_t port, 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
.
The following functions move port receive rights to and from the port structure:
void
ports_reallocate_port (void *port)
¶Destroy the receive right currently associated with port and allocate a new one.
void
ports_reallocate_from_external (void *port, mach_port_t receive)
¶Destroy the receive right currently associated with port and designate receive as the new one.
void
ports_destroy_right (void *port)
¶Destroy the receive right currently associated with port. After
this call, ports_reallocate_port
and
ports_reallocate_from_external
may not be used.
mach_port_t
ports_claim_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.
error_t
ports_transfer_right (void *topt, void *frompt)
¶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).
mach_port_t
ports_get_right (void *port)
¶Return the name of the receive right associated with port. The user is responsible for creating an ordinary send right from this name.
It is important to point out that the port argument to each of
the libports
functions is a void *
and not a struct
port_info *
. This is done so that you may add arbitrary
meta-information to your libports
-managed ports. Simply define
your own structure whose first element is a struct port_info
, and
then you can use pointers to these structures as the port argument
to any libports
function.
The following functions are useful for maintaining metadata that is stored in your own custom ports structure:
void *
ports_lookup_port (struct port_bucket *bucket, mach_port_t port, struct port_class *class)
¶Look up port and return the associated port structure, allocating a reference. If the call fails, return zero. 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.
error_t
ports_bucket_iterate (struct port_bucket *bucket, error_t (*fun) (void *port))
¶Call fun once for each port in bucket. No guarantee is made about the order of iteration, which might vary from call to call. If FUN returns an error, then no further calls to FUN are made for any remaining ports, and the return value of FUN is returned from ports_bucket_iterate.
These functions maintain references to ports so that the port
information structures may be freed if and only if they are no longer
needed. It is your responsibility to tell libports
when
references to ports change.
void
ports_port_ref (void *port)
¶Allocate a hard reference to port.
void
ports_port_deref (void *port)
¶Drop a hard reference to port.
void
ports_no_senders (void *port, mach_port_mscount_t mscount)
¶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.
int
ports_count_class (struct port_class *class)
¶Block creation of new ports in class. Return the number of ports currently in class.
int
ports_count_bucket (struct port_bucket *bucket)
¶Block creation of new ports in bucket. Return the number of ports currently in bucket.
void
ports_enable_class (struct port_class *class)
¶Permit suspended port creation (blocked by ports_count_class
) to
continue.
void
ports_enable_bucket (struct port_bucket *bucket)
¶Permit suspended port creation (blocked by ports_count_bucket
) to
continue.
Weak references are not often used, as they are the same as hard references for port classes where dropweak_routine is null. See Buckets and Classes.
void
ports_port_ref_weak (void *port)
¶Allocate a weak reference to port.
void
ports_port_deref_weak (void *port)
¶Drop a weak reference to port.
The rest of the libports
functions are dedicated to controlling
RPC operations. These functions help you do all the locking and thread
cancellations that are required in order to build robust servers.
typedef
int (*ports_demuxer_type) (mach_msg_header_t *inp, mach_msg_header_t *outp)
¶Type of MiG demuxer routines.
error_t
ports_begin_rpc (void *port, mach_msg_id_t msg_id, struct rpc_info *info)
¶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.
void
ports_end_rpc (void *port, struct rpc_info *info)
¶Call this when an RPC is concluding. The arguments must match the ones
passed to the paired call to ports_begin_rpc
.
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 timeout is nonzero and no messages have been received for timeout milliseconds. Use only one thread (the calling thread).
void
ports_manage_port_operations_multithread (struct port_bucket *bucket, ports_demuxer_type demuxer, int thread_timeout, int global_timeout, void (*hook) (void))
¶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 received 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 thread_timeout is nonzero, then individual threads will die off if they handle no incoming messages for local_timeout milliseconds. If non-null, hook will be called in each new thread immediately after it is created.
error_t
ports_inhibit_port_rpcs (void *port)
¶Interrupt any pending RPC on port. Wait for all pending RPCs to finish, and then block any new RPCs starting on that port.
error_t
ports_inhibit_class_rpcs (struct port_class *class)
¶Similar to ports_inhibit_port_rpcs
, but affects all ports in
class.
error_t
ports_inhibit_bucket_rpcs (struct port_bucket *bucket)
¶Similar to ports_inhibit_port_rpcs
, but affects all ports in
bucket.
error_t
ports_inhibit_all_rpcs (void)
¶Similar to ports_inhibit_port_rpcs
, but affects all ports
whatsoever.
void
ports_resume_port_rpcs (void *port)
¶Reverse the effect of a previous ports_inhibit_port_rpcs
for this
port, allowing blocked RPCs to continue.
void
ports_resume_class_rpcs (struct port_class *class)
¶Reverse the effect of a previous ports_inhibit_class_rpcs
for
class.
void
ports_resume_bucket_rpcs (struct port_bucket *bucket)
¶Reverse the effect of a previous ports_inhibit_bucket_rpcs
for
bucket.
void
ports_resume_all_rpcs (void)
¶Reverse the effect of a previous ports_inhibit_all_rpcs
.
void
ports_interrupt_rpcs (void *port)
¶Cancel (with thread_cancel
) any RPCs in progress on port.
int
ports_self_interrupted (void)
¶If the current thread’s RPC has been interrupted with
ports_interrupt_rpcs
, return nonzero and clear the interrupted
flag.
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 rpc’s thread if
object gets notified that any of the things in what have
happened to port. rpc should be an RPC on object.
error_t
ports_interrupt_self_on_notification (void *object, 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_port_death (void *object, mach_port_t port)
¶Same as calling ports_interrupt_self_on_notification
with
what set to MACH_NOTIFY_DEAD_NAME
.
void
ports_interrupt_notified_rpcs (void *object, mach_port_t port, mach_msg_id_t what)
¶Interrupt any RPCs on object that have requested such.
void
ports_dead_name (void *object, mach_port_t port)
¶Same as calling ports_interrupt_notified_rpcs
with what set
to MACH_NOTIFY_DEAD_NAME
.
libihash
provides integer-keyed hash tables, for arbitrary
element data types. Such hash tables are frequently used when
implementing sparse arrays or buffer caches.
The following functions are declared in <hurd/ihash.h>
:
error_t
ihash_create (ihash_t *ht)
¶Create an integer hash table and return it in ht. If a memory
allocation error occurs, ENOMEM
is returned, otherwise zero.
void
ihash_free (ihash_t ht)
¶Free ht and all resources it consumes.
void
ihash_set_cleanup (ihash_t ht, void (*cleanup) (void *value, void *arg), void *arg)
¶Sets ht’s element cleanup function to cleanup, and its second argument to arg. cleanup will be called on every element value to be subsequently overwritten or deleted, with arg as the second argument.
error_t
ihash_add (ihash_t ht, int id, void *item, void ***locp)
¶Add item to the hash table ht under the integer key
id. locp is the address of a pointer located in item;
If non-null, locp should point to a variable of type void
**
, and will be filled with a pointer that may be used as an argument
to ihash_locp_remove
. The variable pointed to by locp may
be overwritten sometime between this call and when the element is
deleted, so you cannot stash its value elsewhere and hope to use the
stashed value with ihash_locp_remove
. If a memory allocation
error occurs, ENOMEM
is returned, otherwise zero.
void *
ihash_find (ihash_t ht, int id)
¶Find and return the item in hash table ht with key id. Returns null if the specified item doesn’t exist.
error_t
ihash_iterate (ihash_t ht, error_t (*fun) (void *value))
¶Call function fun on every element of ht. fun’s only
arg, value, is a pointer to the value stored in the hash table. If
fun ever returns nonzero, then iteration stops and
ihash_iterate
returns that value, otherwise it (eventually)
returns 0.
int
ihash_remove (ihash_t ht, int id)
¶Remove the entry with a key of id from ht. If there was no such element, then return zero, otherwise nonzero.
void
ihash_locp_remove (ihash_t ht, void **ht_locp)
¶Remove the entry at locp from the hashtable ht. locp
is as returned from an earlier call to ihash_add
. This call
should be faster than ihash_remove
. ht can be null, in
which case the call still succeeds, but no cleanup is done.
The GNU C library is constantly developing to meet the needs of the Hurd. However, because the C library needs to be very stable, it is irresponsible to add new functions to it without carefully specifying their interface, and testing them thoroughly.
The Hurd distribution includes a library called
libshouldbeinlibc
, which serves as a proving ground for additions
to the GNU C library. This library is in flux, as some functions are
added to it by the Hurd developers and others are moved to the official
C library.
These functions aren’t currently documented (other than in their header files), but complete documentation will be added to when these functions become part of the GNU C library.
libhurdbugaddr
exists only to define a single variable:
char *
argp_program_bug_address ¶argp_program_bug_address
is the default Hurd bug-reporting e-mail
address, bug-hurd@gnu.org. This address is displayed to the
user when any of the standard Hurd servers and utilities are invoked
using the ‘--help’ option.