3. Foundations

Every Hurd program accepts the following optional arguments:

`--help'

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.

`--version'

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 section 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.

3.1 Threads Library

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,
libthreads, contains the default Hurd thread implementation, which
is declared in <cthreads.h>.

Currently (April 1998), the Hurd uses cthreads, which have already been
documented thoroughly by CMU. Eventually, it will be migrated to use
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.

3.2 Ports Library

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>.

3.2.1 Buckets and Classes

The libportsbucket is simply a port set, with some
metadata and a lock. All of the libports functions operate on
buckets.

Function: 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.

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:

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.

Destroy the receive right currently associated with port and
designate receive as the new one.

Function: 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.

Function: 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.

Function: 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).

Function: 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.

3.2.3 Port Metadata

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:

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.

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.

3.2.4 Port References

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.

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).

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.

Function: 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.

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.

Function: 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.

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.

Function: 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.

Function: 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.

3.4 Misc Library

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.

3.5 Bug Address Library

libhurdbugaddr exists only to define a single variable:

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.